java interrupt
_灯火阑珊处 人气:0前言:
使用 interrupt 来通知线程停止运行,而不是强制停止!
普通情况停止线程
public class RightWayStopThreadWithoutSleep implements Runnable { @Override public void run() { int num = 0; while (!Thread.currentThread().isInterrupted() && num <= Integer.MAX_VALUE / 2) { if (num % 10000 == 0) { System.out.println(num + "是1W的倍数"); } num++; } System.out.println("任务运行结束!"); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new RightWayStopThreadWithoutSleep()); thread.start(); // 等待1s Thread.sleep(1000); // 通知停止线程 thread.interrupt(); } }
使用 thread.interrupt() 通知线程停止
但是 线程需要配合:
在 while 中使用 Thread.currentThread().isInterrupted() 检测线程当前的状态
运行结果:
……
……
221730000是1W的倍数
221740000是1W的倍数
221750000是1W的倍数
221760000是1W的倍数
221770000是1W的倍数
221780000是1W的倍数
221790000是1W的倍数
221800000是1W的倍数
任务运行结束!Process finished with exit code 0
在可能被阻塞情况下停止线程
public class RightWayStopThreadWithSleep { public static void main(String[] args) throws InterruptedException { Runnable runnable = () -> { int num = 0; while (num <= 300 && !Thread.currentThread().isInterrupted()) { if (num % 100 == 0) { System.out.println(num + "是100的倍数"); } num++; } try { // 等个1秒,模拟阻塞 Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("线程已停止!!"); e.printStackTrace(); } }; Thread thread = new Thread(runnable); thread.start(); // 等待时间要小于上面设置的1秒,不然线程都运行结束了,才执行到下面的thread.interrupt();代码 Thread.sleep(500); // 通知停止线程 thread.interrupt(); } }
线程在sleep 1秒的过程中,收到interrupt信号被打断,
线程正在sleep过程中响应中断的方式就是抛出 InterruptedException 异常
运行结果:
0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
线程已停止!!
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at stopthreads.RightWayStopThreadWithSleep.lambda$main$0(RightWayStopThreadWithSleep.java:19)
at java.lang.Thread.run(Thread.java:748)Process finished with exit code 0
在每次迭代后都阻塞的情况下停止线程
public class RightWayStopThreadWithSleepEveryLoop { public static void main(String[] args) throws InterruptedException { Runnable runnable = () -> { int num = 0; try { while (num <= 10000) { if (num % 100 == 0) { System.out.println(num + "是100的倍数"); } num++; // 每次循环都要等待10毫秒,模拟阻塞 Thread.sleep(10); } } catch (InterruptedException e) { e.printStackTrace(); } }; Thread thread = new Thread(runnable); thread.start(); // 5秒后通知停止线程 Thread.sleep(5000); thread.interrupt(); } }
当每次迭代都会让线程阻塞一段时间的时候,在 while/for 循环条件判断时,
是不需要使用 *Thread.currentThread().isInterrupted() *判断线程是否中断的
运行结果:
0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
400是100的倍数
java.lang.InterruptedException: sleep interrupted
如果将上述代码中的 try/catch 放在 while 循环内:
public class RightWayStopThreadWithSleepEveryLoop { public static void main(String[] args) throws InterruptedException { Runnable runnable = () -> { int num = 0; while (num <= 10000) { if (num % 100 == 0) { System.out.println(num + "是100的倍数"); } num++; try { // 每次循环都要等待10毫秒,模拟阻塞 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread thread = new Thread(runnable); thread.start(); // 5秒后通知停止线程 Thread.sleep(5000); thread.interrupt(); } }
运行结果:
0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
400是100的倍数
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at stopthreads.RightWayStopThreadWithSleepEveryLoop.lambda$main$0(RightWayStopThreadWithSleepEveryLoop.java:18)
at java.lang.Thread.run(Thread.java:748)
500是100的倍数
600是100的倍数
700是100的倍数
……
……
会发现虽然抛出了异常,但是程序并没有停止,还在继续输出,
即使在 while 条件判断处添加 !Thread.currentThread().isInterrupted() 条件,依然不能停止程序!
原因是
java语言在设计 sleep() 函数时,有这样一个理念:
就是当它一旦响应中断,便会把 interrupt 标记位清除。
也就是说,虽然线程在 sleep 过程中收到了 interrupt 中断通知,并且也捕获到了异常、打印了异常信息,
但是由于 sleep 设计理念,导致 Thread.currentThread().isInterrupted() 标记位会被清除,
所以才会导致程序不能退出。
这里如果要停止线程,只需要在 catch 内 再调用一次 interrupt(); 方法
try { // 每次循环都要等待10毫秒,模拟阻塞 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); }
所以说,不要以为调用了 interrupt() 方法,线程就一定会停止。
两种停止线程最佳方法
1. 捕获了 InterruptedException 之后的优先选择:在方法签名中抛出异常
public class RightWayStopThreadInProd implements Runnable { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new RightWayStopThreadInProd()); thread.start(); Thread.sleep(1000); thread.interrupt(); } @Override public void run() { while (true) { System.out.println("go..."); try { throwInMethod(); } catch (InterruptedException e) { // 捕获异常,进行保存日志、停止程序等操作 System.out.println("stop"); e.printStackTrace(); } } } /** * 如果方法内要抛出异常,最好是将异常抛出去,由顶层的调用方去处理,而不是try/catch * 这样调用方才能捕获异常并作出其它操作 * @throws InterruptedException */ private void throwInMethod() throws InterruptedException { Thread.sleep(2000); } }
如果方法内要抛出异常,最好是将异常抛出去,由顶层的调用方去处理,而不是 try/catch
这样调用方才能捕获异常并做出其它操作。
2. 在 catch 中调用 Thread.currentThread().interrupt(); 来恢复设置中断状态
public class RightWayStopThreadInProd2 implements Runnable { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new RightWayStopThreadInProd2()); thread.start(); Thread.sleep(1000); thread.interrupt(); } @Override public void run() { while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("程序运行结束"); break; } reInterrupt(); } } private void reInterrupt() { try { Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } } }
这里的 if (Thread.currentThread().isInterrupted()) 判断,就是要你的代码有响应中断的能力。
总结
- 调用 interrupt 方法不一定会中断线程
- 通知线程停止,线程不会立即停止,而是会在合适的时候停止
- 代码要有响应中断的能力
加载全部内容