Java——多线程之方法详解
Java多线程系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线程的深入剖析。
多线程的常用方法
1、currentThread()方法:
介绍:currentThread()方法可返回该代码正在被哪个线程调用的信息。
示例:
例1:
public class Test01 { public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
} } 结果:
main
结果说明,main方法被名为main的线程调用
例2:
class Mythread extends Thread{ public Mythread() {
System.out.println("构造方法的打印:"+Thread.currentThread().getName());
} @Override
public void run() {
System.out.println("run方法的打印:"+Thread.currentThread().getName());
}
} public class Test01 { public static void main(String[] args) {
Mythread t=new Mythread();
t.start();//①
} } 结果:
构造方法的打印:main
run方法的打印:Thread-0
从结果可知:Mythread的构造方法是被main线程调用的,而run方法是被名称为Thread-0的线程调用的,run方法是线程自动调用的
现在我们将①处的代码改为t.run(),现在的输出结果如下:
构造方法的打印:main
run方法的打印:main
从结果中我们可以看到两次的结果显示都是main线程调用了方法,因为当你使用t.start()方法的时候是线程自动调用的run()方法,所以输出的是Thread-0,当你直接调用run()方法时,和调用普通方法没有什么区别,所以是main线程调用run()
2、isAlive()方法:
介绍:isAlive()方法的功能是判断当前的线程是否处于活动状态
示例:
例1:
class Mythread extends Thread{ @Override
public void run() {
System.out.println("run =="+this.isAlive());
} } public class Test01 { public static void main(String[] args) {
Mythread thread=new Mythread();
System.out.println("begin =="+thread.isAlive());//①
thread.start();//②
System.out.println("end =="+thread.isAlive());//③
} } 结果:
begin ==false
end ==true
run ==true
方法isAlive()的作用是测试线程是否处于活动状态。那么什么情况下是活动状态呢?活动状态就是线程已经启动且尚未停止。线程处于正在运行或准备开始运行的状态,就认为线程是存活的
①处代码的结果为false,因为此时线程还未启动;
②处代码调用了run()方法输出结果为run ==true,此时线程处于活动状态;
③处代码的结果为true,有的同学看到这个输出可能会不理解,不是说线程处于活动状态isAlive()方法的结果才是true,现在程序都已经运行结束了为什么还是true?这里的输出结果是不确定的,我们再来看下面一段代码
我们将例1中的代码稍做修改,代码如下:
public class Test01 { public static void main(String[] args) throws InterruptedException {
Mythread thread=new Mythread();
System.out.println("begin =="+thread.isAlive());//①
thread.start();//②
Thread.sleep(1000);//这里加了一行代码,让当前线程沉睡1秒
System.out.println("end =="+thread.isAlive());//③
} } 结果:
begin ==false
run ==true
end ==false
现在我们看到③处的代码结果为end ==false,因为thread对象已经在1秒内执行完毕,而上面代码输出结果为true是因为thread线程未执行完毕。
3、sleep()方法:
介绍:
方法sleep()的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行),这个“正在执行的线程”是指this.currentThread()返回的线程。
示例:
class Mythread extends Thread{ @Override
public void run() { try {
System.out.println("run threadName="+this.currentThread().getName()+" begin");
Thread.sleep(2000);
System.out.println("run threadName="+this.currentThread().getName()+" end"); } catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } } public class Test01 { public static void main(String[] args) throws InterruptedException {
Mythread thread=new Mythread();
System.out.println("begin ="+System.currentTimeMillis());
thread.run();//①
System.out.println("end ="+System.currentTimeMillis());
} } 结果:
begin =1574660731663
run threadName=main begin
run threadName=main end
end =1574660733665
从结果中可以看出main线程暂停了2秒(因为这里调用的是thread.run())
下面我们将①处的代码改成thread.start(),再来看下运行结果:
begin =1574661491412
end =1574661491412
run threadName=Thread-0 begin
run threadName=Thread-0 end
由于main线程与thread线程是异步执行的,所以首先打印的信息为begin和end,而thread线程是随后运行的,在最后两行打印run begin和run end的信息。
4、getId()方法:
介绍:getId()方法的作用是取得线程的唯一标识
示例:
public class Test01 { public static void main(String[] args) throws InterruptedException {
Thread thread=Thread.currentThread();
System.out.println(thread.getName()+" "+thread.getId());
} } 结果:main 1
从运行结果可以看出,当前执行代码的线程名称是main,线程id值为1
5、停止线程:
介绍:停止线程是在多线程开发时很重要的技术点,掌握此技术可以对线程的停止进行有效的处理。停止线程在Java语言中并不像break语句那样干脆,需要一些技巧性的处理。
在java中有三种方法可以停止线程
- 使用退出标志,让线程正常退出,也就是当run方法执行完之后终止
- 使用stop方法强制终止线程,但是不推荐使用,因为stop和suspend及resume一样,是java废弃的方法
- 使用interrupt方法中断线程(推荐使用)
示例:
例1:
class Mythread extends Thread{ @Override
public void run() { for(int i=0;i<5000;i++) {
System.out.println("i="+(i+1));
}
} } public class Test01 { public static void main(String[] args) throws InterruptedException {
Mythread thread=new Mythread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} }
运行结果:
从运行结果我们可以看出最后i=500000,调用interrupt方法没有停止线程,那么该如何停止线程呢?
在介绍如何停止线程时,我们先来介绍一下如何判断线程是否处于停止状态
Thread类中提供了两种方法用来判断线程是否停止:
1、this.interrupted():测试当前线程是否已经中断,执行后具有将状态标志清除为false的功能
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
2、this.isInterrupted():测试线程Thread对象是否已经中断,但是不清除状态标志
public boolean isInterrupted() {
return isInterrupted(false);
}
读者可以仔细观看一下这两个方法的声明有什么不同?
例2:
class Mythread extends Thread{ @Override
public void run() { for(int i=0;i<5000;i++) {
System.out.println("i="+(i+1));
}
} } public class Test01 { public static void main(String[] args) throws InterruptedException {
Mythread thread=new Mythread();
thread.start();
Thread.sleep(1000);
thread.interrupt();
System.out.println("是否停止1?="+thread.interrupted());
System.out.println("是否停止2?="+thread.interrupted());
System.out.println("end!");
} }
结果:
输出结果显示调用了thread.interrupt()方法后线程并未停止,这也就证明了interrupted()方法的解释:测试当前线程是否已经中断。这个当前线程是main,它从未断过,所以打印的结果是两个false。
如果想让main线程结束该怎么做?
将main方法改成如下:
public class Test01 { public static void main(String[] args) throws InterruptedException {
Thread.currentThread().interrupt();
System.out.println("是否停止1?="+Thread.interrupted());
System.out.println("是否停止2?="+Thread.interrupted());
System.out.println("end!");
} } 结果:
是否停止1?=true
是否停止2?=false
end!
从输出结果我们可以看出,方法interrupted()的确判断出当前线程是否是停止状态。但为什么第2个值是false?
查看一下官方文档的介绍:
测试当前线程是否已经中断。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
文档中说明的非常清楚,interrupted()方法具有清除状态的功能,所以第二次调用interrupted方法返回的值时false。
下面我们来看一下isInterrupted()方法,将main方法改成如下代码:
public static void main(String[] args) throws InterruptedException {
Mythread thread=new Mythread();
thread.start();
thread.interrupt();
Thread.sleep(1000);
System.out.println("是否停止1?="+thread.isInterrupted());
System.out.println("是否停止2?="+thread.isInterrupted());
System.out.println("end");
}
结果: 是否停止1?=true
是否停止2?=true
end
从结果可以看出,方法isInterrrupted()并未清除状态,所以结果为两个true。
例3:在沉睡中停止
当线程调用sleep()方法后再调用interrupt()方法后会有什么结果:
class Mythread extends Thread{ @Override
public void run() { try {
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止,进入catch!"+this.isInterrupted());
e.printStackTrace();
}
} } public class Test01 { public static void main(String[] args) throws InterruptedException {
try {
Mythread thread=new Mythread();
thread.start();
Thread.sleep(200);
thread.interrupt();
}catch(Exception e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
} }
6、暂停线程:
暂停线程意味着此线程还可以恢复运行。在java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行
例1:
class Mythread extends Thread{ private long i=0;
public long getI() {
return i;
} public void setI(long i) {
this.i = i;
} @Override
public void run() {
while(true) {
i++;
}
} } public class Test01 { public static void main(String[] args) throws InterruptedException { Mythread thread=new Mythread();
thread.start();
Thread.sleep(5000);
//A段
thread.suspend();
System.out.println("A= "+System.currentTimeMillis()+" i="+thread.getI());
Thread.sleep(5000);
System.out.println("A= "+System.currentTimeMillis()+" i="+thread.getI()); //B段
thread.resume();
Thread.sleep(5000); //C段
thread.suspend();
System.out.println("B= "+System.currentTimeMillis()+" i="+thread.getI());
Thread.sleep(5000);
System.out.println("B= "+System.currentTimeMillis()+" i="+thread.getI()); } }
结果:
从控制台打印的时间上来看,线程的确被暂停了,而且还可以恢复成运行状态。
7、yield方法:
介绍:yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片
示例:
class Mythread extends Thread{ @Override
public void run() {
long beginTime=System.currentTimeMillis();
int count=0;
for(int i=0;i<500000;i++) {
//Thread.yield();①
count=count+(i+1);
}
long endTime=System.currentTimeMillis();
System.out.println("用时:"+(endTime-beginTime)+"毫秒!");
} } public class Test01 { public static void main(String[] args) throws InterruptedException {
Mythread thread=new Mythread();
thread.start();
} } 结果:用时:2毫秒!
现在将①处的代码取消注释,我们再来看一下运行结果:
用时:213毫秒!
将CPU让给其他资源导致速度变慢
8、线程优先级:
介绍:
在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,也就是CPU优先执行优先级较高的线程对象中的任务。
设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优先执行。
设置线程的优先级使用setPriority()方法,此方法在JDK的源代码如下:
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
在Java中,线程的优先级为1-10这10个等级,如果小于1或大于10,则JDK抛出异常throw new IllegalArgumentException()。
通常高优先级的线程总是先执行完,但是并不是一定的,高优先级和低优先级的线程会交替进行,高优先级执行的次数多一些
线程优先级的继承特性:
在Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。
class Mythread2 extends Thread{
@Override
public void run() {
System.out.println("Mythread2 run priority="+this.getPriority());
}
} class Mythread1 extends Thread{ @Override
public void run() {
System.out.println("Mythread run priority="+this.getPriority());
Mythread2 thread2=new Mythread2();
thread2.start();
} } public class Test01 { public static void main(String[] args) throws InterruptedException { System.out.println("main thread begin priority="+Thread.currentThread().getPriority());
//Thread.currentThread().setPriority(6);①
System.out.println("main thread end priority="+Thread.currentThread().getPriority());
Mythread1 thread1=new Mythread1();
thread1.start();
} } 结果:
main thread begin priority=5
main thread end priority=5
Mythread run priority=5
Mythread2 run priority=5
可以看到上面几个线程的优先级都为5
现在将①处的代码注释掉后的结果是:
main thread begin priority=5
main thread end priority=6
Mythread run priority=6
Mythread2 run priority=6
优先级被更改后再继续继承
9、守护线程:
在java中有两种线程,一种是用户线程,另一种是守护线程。
守护线程是一种特殊的线程,它的特性有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。用个比较通俗的比喻来解释一下:“守护线程”:任何一个守护线程都是整个JVM中所有非守护线程的“保姆”,只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才随着JVM一同结束工作。Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),它就是一个很称职的守护者。
class Mythread extends Thread{ private int i=0; @Override
public void run() { try {
while(true) {
i++;
System.out.println("i="+(i));
Thread.sleep(1000);
}
}catch(Exception e) {
e.printStackTrace();
} } } public class Test01 { public static void main(String[] args) throws InterruptedException { try {
Mythread thread=new Mythread();
thread.setDaemon(true);
thread.start();
Thread.sleep(5000);
System.out.println("我离开Thread对象就不再打印了,也就是停止了");
}catch(Exception e) {
e.printStackTrace();
}
} }
Java——多线程之方法详解的更多相关文章
- java的sleep方法详解
java的sleep方法详解: sleep并不是永久占有CPU,没有那个线程能永久占用CPU.它是指在自己时间片内睡眠,而不是急着交出CPU.yield()就是自己愿意立即交出时间片.因此一个线程sl ...
- java native本地方法详解(转)
文章链接出处: 详解native方法的使用 自己实现一个Native方法的调用 JNI 开始本篇的内容之前,首先要讲一下JNI.Java很好,使用的人很多.应用极 广,但是Java不是完美的.Java ...
- selenium+Java,xpath定位方法详解(搬运留存)
用xpath绝对路径比较费事费力,还容易报错,下面几种模糊定位比较灵活好用 driver.findElement(By.xpath("//*[@id='J_login_form']/dl/d ...
- Java基础之方法详解
方法的所属性 在Java的语言中,方法相当于C语言中的函数,但是它与传统的函数也有着明确的不同:在结构化的语言中,函数是一等公民,整个程序是由一个个函数组成的:但是在面向对象的语言里,类是一等公民,整 ...
- 【多线程】java多线程 测试例子 详解wait() sleep() notify() start() join()方法 等
java实现多线程,有两种方法: 1>实现多线程,继承Thread,资源不能共享 2>实现多线程 实现Runnable接口,可以实现资源共享 *wait()方法 在哪个线程中调用 则当前 ...
- Java 多线程编程知识详解
Java 给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 多线程是多任务的一种特别的形式,但多线程使用 ...
- java线程基础方法详解
一.线程状态转换 1.新建状态(New):新创建了一个线程对象. 2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运行 ...
- Java中常见方法详解合集(方法的定义及语法结构)
Java的方法定义 1.方法的定义 方法是控制对象的动作行为方式与准则,在Java中方法位于类体下又有另一种含义. 普通的方法在类中称为"实例方法",因为方法的调用需要创建对象,而 ...
- java Clone使用方法详解
java"指针" Java语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,本文会试图澄清这一概念.并且由于Java不能 通过 ...
随机推荐
- xftp连接centos7
1.下载xftp文件,并正常进行安装 2.安装好之后运行,并新建会话,此时可见如下界面: 注意: 名称,可随便输入,自己能看懂是什么就行 主机,输入当前Linux服务器的ip(如何获取服务器 ...
- Python分析数据难吗?某科技大学教授说,很难但有方法就简单
用python分析数据难吗?某科技大学的教授这样说,很难,但要讲方法,主要是因为并不是掌握了基础,就能用python来做数据分析的. 所谓python的基础,也就是刚入门的python学习者,学习的基 ...
- 这本最适合夯实基础的经典 Java 书籍,可能80% 的 Java 程序员没有认真看过!
公众号[程序员书单]出品,转载请注明出处 作者:黄小斜 今天要给大家带来的一本书,是大名鼎鼎的head first系列丛书的一本<head first Java>相信很多学习Java的朋友 ...
- 第三章:shell变量知识进阶
特殊变量:位置变量大于9的时候,需要加上(),例如$(10)$*获取脚本的所有参数,如果不加""和$@是一样的效果,如果加上"",则表示所有参数组成一个字符串$ ...
- R - C Looooops POJ - 2115 (exgcd)
题目大意:很好理解,一个for循环语句,从a开始到b结束,步长是c,模数是pow(2,k) 问,最少循环多少次,才能到达b,如果永远都到不了b,输出FOREVER 题解:其实就是求一个线性方程,cx= ...
- XML-解析失败原因初步分析
更多精彩文章请关注公众号『大海的BLOG』 首先放出有问题的代码 之所以直入主题是因为肝完了事情,急需入睡.hiahia hiboard:updateUrl="https://xxx.com ...
- asp.net core web api + Element-UI的Vue管理后台
后端:asp.net core web api + EF Core 前端:VUE + Element-UI+ Node环境的后台管理系统. 线上地址:http://www.wangjk.wang/ 密 ...
- vue如何添加jquery?
1.首选通过npm安装jquery? 2.在build/webpack.base.conf文件当中引入jquery <pre>module.exports = { ... resolve: ...
- SringMVC入门程序
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架 1.Spring优点 轻量级,简单易学 高效 , 基于请求响应的MVC框架 与Spring兼 ...
- liunx常用知识基本命令大全
liunx基础命令使用 标签(空格分隔):liunx常用命令 网络配置 虚拟网卡的绝对路径 /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 ...