停止一个线程的主要机制是中断,中断并不代表强迫终止一个线程,
它是一种协作机制,是给线程传递一个取消的信号,
但是让线程来决定如何以及何时退出。
这句话可谓是线程中断的核心原理了;光看文字还是很模糊的,用代码说事吧。
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()中断