停止一个线程的主要机制是中断,中断并不代表强迫终止一个线程,
它是一种协作机制,是给线程传递一个取消的信号,
但是让线程来决定如何以及何时退出。
这句话可谓是线程中断的核心原理了;光看文字还是很模糊的,用代码说事吧。
1 public class ThreadEnd implements Runnable { 2 3 private volatile static boolean ok=false; 4 @Override 5 public void run() { 6 for(;;){ 7 if(Thread.currentThread().isInterrupted()){ 8 System.out.println("我进入了中断线程的条件中,将要结束run方法"); 9 break;//因为是for死循环,用这种方式退出循环 10 }else{ 11 System.out.println("我没有收到中断信息"); 12 } 13 } 14 } 15 16 17 18 public static void main(String[] args) throws InterruptedException { 19 Thread thread = new Thread(new ThreadEnd()); 20 thread.start(); 21 Thread.sleep(1000); 22 thread.interrupt(); 23 System.out.println("主线程结束"); 24 25 } 26 }
在第6行中不停的死循环来查看线程 isInterrupted()方法是否返回true;
第22行代码给线程调用了线程中断方法,第7行条件满足,最终退出线程。
那么有一个疑问:是不是所有的线程都可以用interrupt()方法进行中断呢?
比如说sleep的线程,比如说等待锁的线程?我们挨个来求解吧。
sleep休眠线程中断代码
1 public class InterruptionSleepThread implements Runnable { 2 3 @Override 4 public void run() { 5 try { 6 System.out.println("本大爷要休眠50秒,你能奈我何?"); 7 Thread.sleep(50000);//休眠50秒 8 } catch (InterruptedException e) { 9 System.out.println("休眠的线程收到中断信号,利用抛异常的方式将本大爷从梦中叫醒,结束线程。"); 10 e.printStackTrace(); 11 } 12 } 13 public static void main(String[] args) throws InterruptedException { 14 Thread thread = new Thread(new InterruptionSleepThread()); 15 thread.start(); 16 Thread.sleep(2000); 17 thread.interrupt(); 18 System.out.println("主线程结束"); 19 20 } 21 }
打印结果
从上面的打印结果来看,休眠的线程是的确退出来了,虽然这个叫醒的方式不怎么优雅(异常的方式)。
这也从另外一个角度告诉了我们,为什么每次在run()里面调用sleep()方法的时候,编译器要我们强制进行异常捕获了,也是为了程序安全。
等待锁的过程中,被中断的代码
1 public class WaitLockThreadInterrupted extends Thread { 2 3 private static Object lock =new Object(); 4 5 @Override 6 public void run() { 7 System.out.println("我要等待test锁释放后,才能执行下面的代码"); 8 synchronized (lock){ 9 while (true){ 10 if(Thread.currentThread().isInterrupted()){ 11 System.out.println("我收到线程中断的信号"); 12 break; 13 }else{ 14 System.out.println("没收到线程中断的信号"); 15 } 16 } 17 } 18 } 19 20 private static void test() throws InterruptedException { 21 synchronized (lock){ 22 Thread thread=new Thread(new WaitLockThreadInterrupted()); 23 thread.start(); 24 Thread.sleep(1000); 25 thread.interrupt(); 26 System.out.println("已发出中断信号"); 27 thread.join();//阻塞test方法,一直到线程thread执行完毕。 28 } 29 } 30 31 public static void main(String[] args) throws InterruptedException { 32 test(); 33 } 34 }
打印结果
虽然打印了结果,但是左边的红灯一直亮着,并且也没有打印11行的内容,表示线程一直没有退出来。
分析代码:test中的synchronized()和run方法中的synchronized用了同一个对象锁,
所以22行的thread线程中的run方法的执行,必须等到test释放掉lock锁对象才行;
但是 test中用thread.join()方法来告诉我们,等thread线程执行完毕了,我才能放你们走。
完了,死锁了。
这种死锁的状态如果25行代码发出中断信号有用的话,这种死锁的尴尬是能够解开的。
从打印结果来看 interrupt()是不能中断等待锁的线程的。
结论:
1.Runnable状态(正在运行或者等待调度的线程)可以用interrupt()中断
2.Block状态(等待锁的线程)不可以用interrupt()中断