中断线程的玩法 interrup()、interrupted()、isInterrupted()

发布时间:2022-03-01 11:04:46 作者:yexindonglai@163.com 阅读(479)

中断线程的使用场景

想象这样一个场景,当我们打开了一个杀毒软件,此时杀毒软件正在扫描你的磁盘文件是否有病毒,但是扫描到一半的时候,你发现电脑太卡了,想要关闭杀毒软件,这时候你点击右上角的 X 按钮,杀毒软件中所有正在扫描的线程就会中断扫描并且关闭线程的执行,当所有线程都退出后,杀毒软件也随之关闭;

中断在计算机中是一个很重要的机制,它决定你了计算机响应速度的快慢,假如没有中断机制,这时候你点击了关闭杀毒软件的按钮,杀毒软件却提示说必须要扫描完才能关闭窗口,你是不是会气的想摔电脑?

interrup()

java中的中断线程方法,需要注意的是,interrup()方法不会中断正在运行的线程,它的作用仅仅只是设置一个中断的标志位,就等于给这个线程设置了一个标签,并不会真正的中断;
在这里插入图片描述

interrupted()

此方法是用来测试中断状态,并且会清除线程的中断状态;返回值为boolean类型, true表示中断,false表示未中断; 所以第一次调用会返回true,同时清除中断标志,当第二次调用时会返回false,表示中断标志已被清除;
在这里插入图片描述

isInterrupted()

isInterrupted() 方法的作用是检查中断标志,判断线程是否被中断,不过isInterrupted只判断是否中断,不会清除中断状态,它的返回值是boolean类型,默认是 false,当我们调用interrup() 方法后,返回值就会变成true

如何中断运行中的线程

有人会说了,既然设置中断状态位不会使线程中断,那我要怎么中断正在运行的程序呢,其实很简单,一般情况下我们都是在循环里面做操作的,如果我们需要中断的时候,使用跳出循环关键字break或者return;返回出去就可以啦!
接下来,我们来一组代码测试下

  1. package com.Lock;
  2. /**
  3. * 线程中断操作
  4. *
  5. * interrupt 不会中断一个正在运行的线程
  6. * interrupt() 仅仅只是打一个停止标志,并不会真正地停止线程
  7. */
  8. public class InterruptTest {
  9. public static void main(String[] args) throws InterruptedException {
  10. Thread thread = new Thread(() -> {
  11. for (int i = 0; i <100 ; i++) {
  12. // 判断是否中断
  13. if(Thread.currentThread().isInterrupted()){
  14. System.out.println("我已经停止了"+i);
  15. System.out.println("清除标志:"+Thread.interrupted());
  16. System.out.println("清除标志2:"+Thread.interrupted());
  17. // 退出线程
  18. break;
  19. } else {
  20. System.out.println("我正在运行中" + i);
  21. }
  22. }
  23. });
  24. thread.start();
  25. System.out.println("中断");
  26. // 设置中断标志
  27. thread.interrupt();
  28. }
  29. }

打印结果可以看到,设置中断标志后,因为break的原因,线程立马停止了运行;并且在清除中断标志时,第一次返回true,第二次返回了false
在这里插入图片描述

interrupted()方法的坑

需要特别注意interrupted()这个方法,通过源码可以看到,里面是直接清除currentThread() 的中断标志,也就是说,你在哪个线程中调用interrupted() ,清除的就是哪个线程的中断标志;
在这里插入图片描述
接下来,我们用一组代码测试下,在下面的代码中,先中断T1线程, 然后在主线程中清除中断状态,但是这个清除操作是在main方法的线程里面操作的,就相当于调用了main.interrupted() ,所以T1线程的中断状态不会清除,因此下面的代码执行完后,T1线程依然还是中断状态

  1. package com.Lock;
  2. /**
  3. * 线程中断操作
  4. *
  5. * interrupt 不会中断一个正在运行的线程
  6. * interrupt() 仅仅只是打一个停止标志,并不会真正地停止线程
  7. */
  8. public class InterruptTest {
  9. public static void main(String[] args) throws InterruptedException {
  10. Thread thread = new Thread(() -> {
  11. for (int i = 0; i <50 ; i++) {
  12. // 判断是否中断
  13. if(Thread.currentThread().isInterrupted()){
  14. System.out.println(Thread.currentThread().getName()+"已经中断了"+i);
  15. } else {
  16. System.out.println(Thread.currentThread().getName()+"正在运行中" + i);
  17. }
  18. }
  19. });
  20. thread.start();
  21. System.out.println("中断");
  22. // 设置中断标志
  23. thread.interrupt();
  24. System.out.println("恢复");
  25. // 恢复中断的线程(只能恢复当前中断的线程,在同一个线程下 thread.interrupted() 和Thread.interrupted() 没有区别,这里清除的是主线程的中断状态
  26. thread.interrupted();
  27. }
  28. }

运行后,果然不出我所料,T1线程还是中断的

  1. 中断
  2. T1正在运行中0
  3. T1已经中断了1
  4. T1已经中断了2
  5. 恢复
  6. T1已经中断了3
  7. T1已经中断了4
  8. T1已经中断了5
  9. T1已经中断了6
  10. T1已经中断了7
  11. T1已经中断了8
  12. T1已经中断了9
  13. T1已经中断了10
  14. T1已经中断了11
  15. T1已经中断了12
  16. T1已经中断了13
  17. T1已经中断了14
  18. T1已经中断了15
  19. T1已经中断了16
  20. T1已经中断了17
  21. T1已经中断了18
  22. T1已经中断了19
  23. T1已经中断了20
  24. T1已经中断了21
  25. T1已经中断了22
  26. T1已经中断了23
  27. T1已经中断了24
  28. T1已经中断了25
  29. T1已经中断了26
  30. T1已经中断了27
  31. T1已经中断了28
  32. T1已经中断了29
  33. T1已经中断了30
  34. T1已经中断了31
  35. T1已经中断了32
  36. T1已经中断了33
  37. T1已经中断了34
  38. T1已经中断了35
  39. T1已经中断了36
  40. T1已经中断了37
  41. T1已经中断了38
  42. T1已经中断了39
  43. T1已经中断了40
  44. T1已经中断了41
  45. T1已经中断了42
  46. T1已经中断了43
  47. T1已经中断了44
  48. T1已经中断了45
  49. T1已经中断了46
  50. T1已经中断了47
  51. T1已经中断了48
  52. T1已经中断了49
  53. Process finished with exit code 0

接下来我们改一下代码,在T1线程中恢复中断状态

  1. package com.Lock;
  2. /**
  3. * 线程中断操作
  4. *
  5. * interrupt 不会中断一个正在运行的线程
  6. * interrupt() 仅仅只是打一个停止标志,并不会真正地停止线程
  7. */
  8. public class InterruptTest {
  9. public static void main(String[] args) throws InterruptedException {
  10. Thread thread = new Thread(() -> {
  11. for (int i = 0; i <50 ; i++) {
  12. // 判断是否中断
  13. if(Thread.currentThread().isInterrupted()){
  14. System.out.println(Thread.currentThread().getName()+"已经中断了"+i);
  15. System.out.println("恢复");
  16. // 在T1线程清除中断标志
  17. Thread.interrupted();
  18. } else {
  19. System.out.println(Thread.currentThread().getName()+"正在运行中" + i);
  20. }
  21. }
  22. },"T1");
  23. thread.start();
  24. System.out.println("中断");
  25. // 设置中断标志
  26. thread.interrupt();
  27. }
  28. }

通过结果可以看到,已经清除了T1线程的中断标志

  1. 中断
  2. T1正在运行中0
  3. T1已经中断了1
  4. 恢复
  5. T1正在运行中2
  6. T1正在运行中3
  7. T1正在运行中4
  8. T1正在运行中5
  9. T1正在运行中6
  10. T1正在运行中7
  11. T1正在运行中8
  12. T1正在运行中9
  13. T1正在运行中10
  14. T1正在运行中11
  15. T1正在运行中12
  16. T1正在运行中13
  17. T1正在运行中14
  18. T1正在运行中15
  19. T1正在运行中16
  20. T1正在运行中17
  21. T1正在运行中18
  22. T1正在运行中19
  23. T1正在运行中20
  24. T1正在运行中21
  25. T1正在运行中22
  26. T1正在运行中23
  27. T1正在运行中24
  28. T1正在运行中25
  29. T1正在运行中26
  30. T1正在运行中27
  31. T1正在运行中28
  32. T1正在运行中29
  33. T1正在运行中30
  34. T1正在运行中31
  35. T1正在运行中32
  36. T1正在运行中33
  37. T1正在运行中34
  38. T1正在运行中35
  39. T1正在运行中36
  40. T1正在运行中37
  41. T1正在运行中38
  42. T1正在运行中39
  43. T1正在运行中40
  44. T1正在运行中41
  45. T1正在运行中42
  46. T1正在运行中43
  47. T1正在运行中44
  48. T1正在运行中45
  49. T1正在运行中46
  50. T1正在运行中47
  51. T1正在运行中48
  52. T1正在运行中49
  53. Process finished with exit code 0

当中断线程遇到阻塞方法 wait()join()sleep()

当线程处于阻塞状态,调用 wait()join()sleep()方法时;调用线程对象的interrupt()方法会清除中断状态,并得到一个InterruptedException异常。
在这里插入图片描述

还是上代码吧,直观些

  1. package com.Lock;
  2. /**
  3. * 线程中断操作
  4. * <p>
  5. * interrupt 不会中断一个正在运行的线程
  6. * interrupt() 仅仅只是打一个停止标志,并不会真正地停止线程
  7. */
  8. public class InterruptTest {
  9. public static void main(String[] args) throws InterruptedException {
  10. Thread thread = new Thread(() -> {
  11. for (int i = 0; i < 50; i++) {
  12. // 判断是否中断
  13. if (Thread.currentThread().isInterrupted()) {
  14. System.out.println(Thread.currentThread().getName() + "已经中断了" + i);
  15. try {
  16. // 线程在阻塞状态下被中断时,首先会先清除中断标志,并得到一个InterruptedException 异常
  17. Thread.sleep(1000);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. } else {
  22. System.out.println(Thread.currentThread().getName() + "正在运行中" + i);
  23. }
  24. }
  25. }, "T1");
  26. thread.start();
  27. System.out.println("中断");
  28. // 设置中断标志
  29. thread.interrupt();
  30. }
  31. }

打印结果可以看到,虽然已经被中断,但是打印的结果仍然是运行中的日志,并抛出了异常,所以根据此次结果断定,在阻塞时设置中断状态会被恢复,并抛出异常!

  1. 中断
  2. T1正在运行中0
  3. T1已经中断了1
  4. T1正在运行中2
  5. T1正在运行中3
  6. T1正在运行中4
  7. T1正在运行中5
  8. T1正在运行中6
  9. T1正在运行中7
  10. T1正在运行中8
  11. T1正在运行中9
  12. T1正在运行中10
  13. T1正在运行中11
  14. T1正在运行中12
  15. T1正在运行中13
  16. T1正在运行中14
  17. T1正在运行中15
  18. T1正在运行中16
  19. T1正在运行中17
  20. T1正在运行中18
  21. T1正在运行中19
  22. T1正在运行中20
  23. T1正在运行中21
  24. T1正在运行中22
  25. T1正在运行中23
  26. T1正在运行中24
  27. T1正在运行中25
  28. T1正在运行中26
  29. T1正在运行中27
  30. T1正在运行中28
  31. T1正在运行中29
  32. T1正在运行中30
  33. T1正在运行中31
  34. T1正在运行中32
  35. T1正在运行中33
  36. T1正在运行中34
  37. T1正在运行中35
  38. T1正在运行中36
  39. T1正在运行中37
  40. T1正在运行中38
  41. T1正在运行中39
  42. T1正在运行中40
  43. T1正在运行中41
  44. T1正在运行中42
  45. T1正在运行中43
  46. T1正在运行中44
  47. T1正在运行中45
  48. T1正在运行中46
  49. T1正在运行中47
  50. T1正在运行中48
  51. T1正在运行中49
  52. java.lang.InterruptedException: sleep interrupted
  53. at java.lang.Thread.sleep(Native Method)
  54. at com.Lock.InterruptTest.lambda$main$0(InterruptTest.java:20)
  55. at java.lang.Thread.run(Thread.java:748)
  56. Process finished with exit code 0

java 的线程中断是不是很简单呢? 其实java作为面向对象的语言,大部分的功能用起来都是很简单的,只是原理稍微复杂些,但是只要肯钻研下去,等你学会之后也不会觉得很复杂!

关键字Java