你真的了解Java中的interrupt()中断线程吗?
2017-05-11 12:47
489 查看
很多Java初级开发者(包括我)都知道终止一个正在运行的线程最好的方法不是
JDK已废弃的stop()方法,而是用interrupt()或条件变量,但事实上真就那么简单吗?
很多东西一旦涉及到多线程,问题就复杂起来,你必须考虑很多问题。
今天我们就好好聊聊Java中的一个interrupt()中断线程方法,同时涉及到了很多其
他问题(都是坑啊,一不小心就进去了)。
中断可以理解为线程的一个标志位属性,它表示一个运行中的线程是否被其他线程
进行了中断操作。中断好比其它线程对该线程打了个招呼,其它线程通过调用该线程的
interrupt()方法对其进行中断操作,相当于将该线程的中断标志位设置为true,而被中
断的线程自身通过检查中断标志位做出中断响应,说白了,就是我们程序员自己写中断
处理程序的代码(因为JDK的开发者并不知道我们中断线程后如何处理未完成的任务)。
这里演示一段代码,表明单纯用interrupt()中断线程方法并不能停止当前正在运行的线
程,需要配合其它方法才能正确停止线程。
看控制台输出结果:
可见,线程一直打印到50000,执行完毕后退出线程,并没有我们预料中在某处中断。
结论:单纯用interrupt()中断线程方法并不能停止当前正在运行的线程,需要配合
其它方法才能正确停止线程。
这里的其它方法包括:interrupted()与isInterrupted(),两者都是判断当前线程
的中断标志位是否为true,两者都是唯一区别是,前者会读取并清除中断状态,后者仅读取状态。意思是,假如当前线程已经被调用interrupt()方法将中断标志位设为true,那么在调用interrupted()方法首先会返回一个true,然后将其中断标志位设为false,而如果调用isInterrupted()方法,始终会返回true,其中断标志位不变。程序中建议慎用interrupted()方法,而使用isInterrupted()方法,不过应根据业务需求和底层原理灵活使用,这就考虑程序员的能力了。下面配合isInterrupted()方法完成对上面代码的改进,让其在某处中断下来。
看控制台输出结果:
这里完成了一个简单的中断处理程序。但令人困惑的还不止这两个方法,我们在继
续深入下去,最后给出Java中断线程的最佳实践和模板代码。
当一个正在运行的线程遇到阻塞时,中断该线程的情况将变得更加复杂和麻烦,这
里为方便起见,仅举出遇到wait/sleep/join阻塞后,调用interrupt()方法的情况。
查阅JDK文档,可知:如果该线程正阻塞于Object类的wait()、wait(long)、
wait(long, int)方法,或者Thread类的join()、join(long)、join(long, int)、sleep(long)、sleep(long, int)方法,则该线程的中断状态将被清除(即中断标志位设为false),并收到一个java.lang.InterruptedException。
因此,(画重点,敲黑板!)在编写多线程代码的时候,任何时候捕获到
InterruptedException,要么继续上抛,要么重置中断状态,这是最安全的做法.
模板代码:
这里举个例子:
看控制台输出结果:
假如将13行注释起来,线程将无法中断,一直循环下去。
所以说,线程中断还真不是一个简单的问题,中断后的处理程序要程序员自己写,
一定要慎之又慎。在工作中必须灵活运用,知道原理和处理方法。
JDK已废弃的stop()方法,而是用interrupt()或条件变量,但事实上真就那么简单吗?
很多东西一旦涉及到多线程,问题就复杂起来,你必须考虑很多问题。
今天我们就好好聊聊Java中的一个interrupt()中断线程方法,同时涉及到了很多其
他问题(都是坑啊,一不小心就进去了)。
中断可以理解为线程的一个标志位属性,它表示一个运行中的线程是否被其他线程
进行了中断操作。中断好比其它线程对该线程打了个招呼,其它线程通过调用该线程的
interrupt()方法对其进行中断操作,相当于将该线程的中断标志位设置为true,而被中
断的线程自身通过检查中断标志位做出中断响应,说白了,就是我们程序员自己写中断
处理程序的代码(因为JDK的开发者并不知道我们中断线程后如何处理未完成的任务)。
这里演示一段代码,表明单纯用interrupt()中断线程方法并不能停止当前正在运行的线
程,需要配合其它方法才能正确停止线程。
public class InterruptDemo { static class MyRunnable implements Runnable{ public void run() { for(int i=0;i<50000;i++) { System.out.println("i="+(i+1)); } } } public static void main(String[] args) { Thread t=new Thread(new MyRunnable()); t.start(); t.interrupt(); } }
看控制台输出结果:
可见,线程一直打印到50000,执行完毕后退出线程,并没有我们预料中在某处中断。
结论:单纯用interrupt()中断线程方法并不能停止当前正在运行的线程,需要配合
其它方法才能正确停止线程。
这里的其它方法包括:interrupted()与isInterrupted(),两者都是判断当前线程
的中断标志位是否为true,两者都是唯一区别是,前者会读取并清除中断状态,后者仅读取状态。意思是,假如当前线程已经被调用interrupt()方法将中断标志位设为true,那么在调用interrupted()方法首先会返回一个true,然后将其中断标志位设为false,而如果调用isInterrupted()方法,始终会返回true,其中断标志位不变。程序中建议慎用interrupted()方法,而使用isInterrupted()方法,不过应根据业务需求和底层原理灵活使用,这就考虑程序员的能力了。下面配合isInterrupted()方法完成对上面代码的改进,让其在某处中断下来。
public class InterruptDemo2 { static class MyRunnable implements Runnable{ public void run() { for(int i=0;!Thread.currentThread().isInterrupted()&&i<50000;i++) { System.out.println("i="+(i+1)); } } } public static void main(String[] args) throws InterruptedException { Thread t=new Thread(new MyRunnable()); t.start(); Thread.currentThread().sleep(5);//让线程运行一段时间 t.interrupt(); t.join();//等待指定的线程终止 System.out.println("end"); }
看控制台输出结果:
这里完成了一个简单的中断处理程序。但令人困惑的还不止这两个方法,我们在继
续深入下去,最后给出Java中断线程的最佳实践和模板代码。
当一个正在运行的线程遇到阻塞时,中断该线程的情况将变得更加复杂和麻烦,这
里为方便起见,仅举出遇到wait/sleep/join阻塞后,调用interrupt()方法的情况。
查阅JDK文档,可知:如果该线程正阻塞于Object类的wait()、wait(long)、
wait(long, int)方法,或者Thread类的join()、join(long)、join(long, int)、sleep(long)、sleep(long, int)方法,则该线程的中断状态将被清除(即中断标志位设为false),并收到一个java.lang.InterruptedException。
因此,(画重点,敲黑板!)在编写多线程代码的时候,任何时候捕获到
InterruptedException,要么继续上抛,要么重置中断状态,这是最安全的做法.
模板代码:
public void run() { try { // ① 调用阻塞方法 } catch (InterruptedException e) { Thread.currentThread().interrupt(); // ② 恢复被中断的状态 } }
这里举个例子:
public class InterruptDemo3 { static class MyRunnable implements Runnable{ public void run() { while(!Thread.currentThread().isInterrupted()){ try { System.out.println("sleep begin!"); Thread.currentThread().sleep(1000); System.out.println("sleep end!"); } catch (InterruptedException e) { System.out.println("睡眠中遇中断进入catch,重置中断标志位,退出循环!"); Thread.currentThread().interrupt(); } } System.out.println("中断后正常退出"); } } public static void main(String[] args) throws InterruptedException { Thread t=new Thread(new MyRunnable()); t.start(); Thread.currentThread().sleep(1000);//让线程t运行一段时间 t.interrupt(); } }
看控制台输出结果:
假如将13行注释起来,线程将无法中断,一直循环下去。
所以说,线程中断还真不是一个简单的问题,中断后的处理程序要程序员自己写,
一定要慎之又慎。在工作中必须灵活运用,知道原理和处理方法。
相关文章推荐
- Android Thread interrupt 中断JAVA线程
- java线程中断[interrupt()函数]
- 用interrupt()中断Java线程
- Java中的线程中断:interrupt()、interrupted()和isInterrupted
- Android Thread interrupt 中断JAVA线程(转)
- Java Thread.interrupt( )中断线程
- Java Thread.interrupt 中断JAVA线程
- Java Thread.interrupt 害人! 中断JAVA线程(zz)
- Java Thread.interrupt 害人! 中断JAVA线程
- Java Thread.interrupt 害人! 中断JAVA线程(zz)
- java Thread 线程的中断 interrupt
- java线程中断[interrupt()函数] (转载)
- Java Thread.interrupt 中断JAVA线程
- Java_Thread_interrupt中断线程
- Android Thread interrupt 中断JAVA线程
- Java Thread.interrupt 害人! 中断JAVA线程(zz)
- 用interrupt()中断Java线程
- 用interrupt()中断Java线程
- java中 sleep线程睡眠 Join线程独占 Yeile 线程让步 Interrupt线程中断 Deamon后台线程
- 用interrupt()中断Java线程