前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java多线程三:线程中断

Java多线程三:线程中断

作者头像
全栈学习笔记
发布2022-06-14 12:34:10
发布2022-06-14 12:34:10
52000
代码可运行
举报
文章被收录于专栏:全栈学习笔记全栈学习笔记
运行总次数:0
代码可运行

有线程运行,肯定就会有线程中断,在Java语言中,线程中断是一种协作机制,通过对线程设置中断标记,告知对应的线程,根据中断标记来决定是否需要中断当前线程。也就是说,在线程运行过程中,其实我们没有办法安全,准确的终止一个线程。

线程中断涉及的几个方法
interrupt()

设置线程中断标志,所在线程调用该方法之后,正常情况下会设置一个线程中断标志位 interrupt = true.(此时调用interrupted或者是isInterrupted就会返回true),如果该线程处于等待,阻塞,或者无限期等待状态,那么就会抛出InterruptedException异常,从而提前结束线程。但是不能中断I/O阻塞和synchronized锁阻塞。

sleep方法

代码语言:javascript
代码运行次数:0
运行
复制
Thread thread = new Thread(()->{
     try {
         Thread.sleep(10000);
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
 });
 thread.start();
 thread.interrupt();
 
 会抛出异常 java.lang.InterruptedException: sleep interrupted

wait方法

代码语言:javascript
代码运行次数:0
运行
复制
 public class InterruptTest {
     private static String str = "test";
     public static void main(String[] args) {
         Thread thread = new Thread(()->{
             synchronized (str){
                 try {
                     str.wait();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         });
         thread.start();
         thread.interrupt();
     }
 }
 抛出异常:java.lang.InterruptedException

join方法

代码语言:javascript
代码运行次数:0
运行
复制
 Thread thread1 = new Thread(()->{
     while (true){
 
     }
 });
 Thread thread = new Thread(()->{
     try {
         thread1.join();
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
 });
 thread1.start();
 thread.start();
 thread.interrupt();
 
 抛出异常:java.lang.InterruptedException

synchronized锁阻塞测试:

代码语言:javascript
代码运行次数:0
运行
复制
public class InterruptTest {
     private static String str = "test";
     public static void main(String[] args) {
         Thread thread2 = new Thread(() -> {
             synchronized (str) {
                 while (true){
                 
                 }
             }
         });
         thread2.start();
         thread2.interrupt();
         System.out.println(thread2.isInterrupted());
         Thread.sleep(1000);
         Thread thread3 = new Thread(() -> {
             synchronized (str) {
                 System.out.println("拿到锁了");
             }
         });
         thread3.start();
         thread3.interrupt();
         System.out.println(thread3.isInterrupted());
     }
 }
 //运行结果
 true
 true

结果分析:不管是在已经获取到锁,执行业务代码的时候还是在未获取到锁,等待获取锁的过程中,即使调用了interrupt方法,将当前线程中断标志置为true,当前线程既不会被中断,也不会抛出InterruptedException。 在测试中,为了保证测试的线程在执行interrupt方法执行之前已经处于运行状态,建议让主线程阻塞一段时间

isInterrupted()

返回一个线程打断标记,布尔类型。

对于上面的sleep,wait,join这种被打断的线程,这个方法会返回false,意思是调用了sleep,wait,join这类方法,会将打断标记清除,在某一时刻是true,但是最终是false。以sleep为例

代码语言:javascript
代码运行次数:0
运行
复制
Thread thread1 = new Thread(()->{
     try {
         Thread.sleep(5000);
     } catch (InterruptedException e) {
         e.printStackTrace();
         // 在这里打印当前线程的状态一定是false
         //System.out.println(Thread.currentThread().isInterrupted());
     }
 });
 thread1.start();
 try {
     Thread.sleep(1000);
 
 } catch (InterruptedException e) {
     e.printStackTrace();
 }
 System.out.println(thread1.isInterrupted());
 thread1.interrupt();
 System.out.println(thread1.isInterrupted());
 
 //运行结果
 false
 false  //这里也有可能打印true  
 java.lang.InterruptedException: sleep interrupted

上面的运行结果第二行,也就是当我调用了interrupt方法之后立即调用isInterrupted方法,这里有可能会是true, 原因在于当sleep方法抛出异常的时候,才将线程的中断状态置为false,当调用了interrupt方法的时候,线程状态为true。

对于正常的一直在运行的线程,调用了interrupt方法之后,不会清除打断标记。

代码语言:javascript
代码运行次数:0
运行
复制
 Thread thread = new Thread(()->{
     while(true){
     }
 });
 thread.start();
 try {
     Thread.sleep(1000);
 } catch (InterruptedException e) {
     e.printStackTrace();
 }
 System.out.println(thread.isInterrupted());
 thread.interrupt();
 System.out.println(thread.isInterrupted());
 
 //运行结果
 false
 true

线程会一直运行下去,不会受到线程中断的影响,即使中断标志位为true。但是我们可以根据线程中断标志,来判断当前线程是否可以继续运行。

对线程稍微改造一下,让他在线程中断为true的时候退出线程运行。

代码语言:javascript
代码运行次数:0
运行
复制
 Thread thread = new Thread(()->{
      while(true){
          if(!Thread.currentThread().isInterrupted()){
              System.out.println("线程该中断了!做完这一点活就退休");
              System.out.println("再干一点点");
              break;
          }
      }
  });

其他运行代码不变,看运行结果

interrupted()

这是一个静态方法,用的比较少。其实原理和isInterrupted是差不多的,区别在于isInterrupted不会清除中断标志,interrupted会将中断标志清除,也就是说,我们调用了isInterrupted 之后,对于正常在执行的线程,他的中断标志一直是true,但是我们调用了interrupted方法之后,只有在执行了interrupt之后到我们执行interrupted之前为true,在之后就是false。

JDK源码中的解释:测试当前线程是否被中断。该方法清除线程的中断状态。换句话说,如果这个方法被连续调用两次,第二次调用将返回 false(除非当前线程再次被中断,在第一次调用清除其中断状态之后,第二次调用检查它之前)。由于在中断时线程不活动而被忽略的线程中断将通过此方法返回 false 来反映。

总结

线程中断对于我们学习多线程还是有很大的帮助,线程中断本质上不会强制将线程停止,如果需要强制将线程终止,可以调用Thread 中的stop()方法,但是不建议这么用,该方法已经过时,学习了线程中断,我们就可以根据线程中断标志来更加优雅的停止线程。

文中有错误的地方也希望大佬们能指出来

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程中断涉及的几个方法
    • interrupt()
    • isInterrupted()
    • interrupted()
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档