写点什么

【并发编程系列 1】Thread 生命周期及 interrupted() 作用分析

  • 2022 年 4 月 15 日
  • 本文字数:2631 字

    阅读完需:约 9 分钟



可运行状态或者说就绪状态。当我们调用 thread.start()之后,线程就进入 RUNNABLE 状态,注意,调用 start()方法之后线程并不一定会马上执行,还要看操作系统的调度才能执行。


package com.zwx.thread;


public class ThreadState {


public static void main(String[] args) {


Thread t1 = new Thread(()->{


System.out.println("我是 t1 线程");


});


System.out.println(t1.getState());//NEW


t1.start();


System.out.println(t1.getState());//RUNNABLE


}


}


上面的第二个输出语句中线程 t1 的状态就是 RUNNABLE 状态


[](()TERMINATED




package com.zwx.thread;


public class ThreadState {


public static void main(String[] args) throws InterruptedException {


Thread t1 = new Thread(()->{


System.out.println("我是 t1 线程");


});


System.out.println(t1.getState());//NEW


t1.start();


Thread.sleep(1000);


System.out.println(t1.getState());//TERMINATED


}


}


t1 线程启动之后,我们把主线程休眠 1s,t1 执行完毕之后再看 t1 的状态就是 TERMINATED


[](()WAITING




等待状态,当调用 wait(),join()或者 park()方法时,线程就会处于 WAITING 等待状态


package com.zwx.thread;


public class ThreadState {


public static void main Java 开源项目【ali1024.coding.net/public/P7/Java/git】 (String[] args) throws InterruptedException {


new Thread(()->{


while (true){


synchronized (ThreadState.class){


System.out.println("我是 t1 线程");


try {


ThreadState.class.wait();


} catch (InterruptedException e) {


e.printStackTrace();


}


}


}


},"t1").start();


new Thread(()->{


while (true){


System.out.println("我是 t2 线程");


try {


Thread.sleep(20000);


} catch (InterruptedException e) {


e.printStackTrace();


}


}


},"t2").start();


}


}


运行之后通过 jps 和 jstack 命令可以看到 t2 线程就是 TIMED_WAITING 状态,而 t1 就是 WAITING 状态



[](()TIMED_WAITING




和上面 WAITING 状态一样,只是有一个等待时间,一般调用如下方法时:sleep(),wait(),join(),LockSupport.parkNanos(),LockSupport.parkUntil(),而且方法带上时间则线程会出现这个状态。


示例同上面的 WAITING 中的示例


[](()BLOCKED




线程等待锁时被阻塞状态。一个线程正在等待进入一个同步代码块时线程会被阻塞或者被调用之后重入一个同步代码块时被阻塞。


package com.zwx.thread;


public class ThreadState {


static class BlockDemo extends Thread{


@Override


public void run() {


synchronized (BlockDemo.class){


while (true){


}


}


}


}


public static void main(String[] args) {


new Thread(new BlockDemo(),"t3").start();


new Thread(new BlockDemo(),"t4").start();


}


}


上面示例中 t3 和 t4 争抢同一把锁进入同步代码块,那么一定会有一个线程处于 BLOCKED 状态:



[](()线程生命周期图




经过上面的分析,我们可以得到一张线程的生命 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 周期简图:



[](()interrupted()作用


============================================================================


线程当中有三个关于中断的方法:


  • interrupt():打一个中断标记,并没有实际去中断一个线程。

  • isInterrupted():如果调用了 interrupt()方法,则这里会输出 true,表示当前线程被中断过。

  • interrupted():静态方法。如果调用了 interrupt()方法,则这里会输出 true,表示当前线程被中断过,但是这个方法比上面的 isInterrupted()方法多做了一件事,那就是线程复位,也就是说,连续两次调用 interrupted()方法后,第一次为 true,第二次就会变回 false。


我们来看下面一个例子:


package com.zwx.thread.baseapi;


public class ThreadInterruptDemo {


public static void main(String[] args) throws InterruptedException {


Thread t1 = new Thread(()->{


int i=0;


while(Thread.interrupted()){


System.out.println("我是线程" + Thread.currentThread().getName() + ":" + Thread.interrupted());//false


}


},"t1");


t1.start();


t1.interrupt();


}


}


这里的输出结果为 false,这是因为判断条件里面调用了一次为 true,然后对线程进行了复位,所以 run()方法内输出了 false。


实际上: isInterrupted()和 interrupted()方法最终都调用的是下面这个本地方法,只不过 isInterrupted()方法默认传了 false(不复位),而 interrupted()默认传了 true(复位)



线程中断标记有什么用呢?


这是因为我们并不建议直接去中断一个线程,假如一个线程正在执行一系列操作,那么强行中断,可能会引起其他问题(这也是 stop()方法之所以标记为过期的原因),所以中断只是打一个标记,然后由线程自己去获取中断标记,再决定要不要中断。


就比如我们上面的 while 循环中,我们获取到中断标记,然后内部可以决定是继续执行循环体还是直接返回终止线程。


为什么需要对线程复位?


我们设想这么一种场景,假如我们规定收到 3 次线程中断要求的时候,即使线程没有执行完毕这时候也需要直接返回,那么线程如果不复位,我们就没办法知道当前线程进行过多少次中断(不考虑同时多次中断的情况),因为中断过一次,一直是 true;而有了线程复位,我们就只需要判断 3 次都是 true 就说明至少被中断过 3 次。


[](()当 interrupt()遇到 sleep()


==================================================================================


我们都知道,每次调用 sleep()的时候都需要抛出一个 InterruptedException 异常


老规矩,还是来看一个例子:


package com.zwx.thread.baseapi;


public class InterruptSleepThreadDemo {


public static void main(String[] args) throws InterruptedException {


Thread t1 = new Thread(()->{


try {


Thread.sleep(10000);


} catch (InterruptedException e) {


System.out.println(Thread.currentThread().isInterrupted());//false


}


},"t1");


t1.start();


Thread.sleep(1000);


t1.interrupt();


}


}


这里输出结果为 false,这就说明当我们一个休眠的线程被中断后,抛出异常的同时也会对线程的中断标记进行复位,这一点是需要注意的


[](()currentThread()和 this 的区别


====================================================================================


我们还是先来看下面的一个例子:


package com.zwx.thread.baseapi;



最近我根据上述的技术体系图搜集了几十套腾讯、头条、阿里、美团等公司 21 年的面试题,把技术点整理成了视频(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分



用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
【并发编程系列1】Thread生命周期及interrupted()作用分析_Java_爱好编程进阶_InfoQ写作平台