java多线程并发(三)(中断线程)
2013-09-11 17:50
411 查看
转自:http://blog.psjay.com/posts/summary-of-java-concurrency-three-interrupt/
新建状态(New):一个新的线程在被创建之后,在运行(或阻塞)之前的状态。
就绪状态(Runnable):当一个线程只要拥有CPU时间片就能运行的时候,这个线程就处于就绪状态。
阻塞状态(Blocked):线程还没有死亡,但是由于一些原因不能继续运行,但是还能回到就绪状态。
死亡状态(Dead):当一个线程的任务已经完成,即run方法已经正确返回,或者被中断,这个线程就处于死亡状态。
调用了Thread.sleep()方法;
调用了wait(),线程被挂起;
线程在等待其他操作完成。例如正在等待输入;
线程在等待其他线程持有的锁。
Interrupts this thread.
但是,这个方法能不能真的轻而易举地中断一个线程呢?我们可以用下面的代码进行测试:
impleThread继承了Thread,它的run()方法就是不断地将“i am doing my job!”这句话打印到控制台。在测试类的主方法中启动了一个这样的线程,并且主线程打算在2秒之后中断这个线程。可是运行的结果并不是我们预期的那样:控制台还是不断地在打印“I am doing my job!”。
看来,interrupt()方法并没有成功的中断我们的线程。那么interrupt()方法到底做了些什么呢?
为了便于理解,其实可以这样来类比(注意,只是类比,实际情况并不完全是这样):Thread类中有一个boolean的标志域用来表示线程是否需要被中断,默认是false。interrupt()方法被调用之后,这个标志域就变成了true。当然,Thread类有一个interrupted()方法返回一个boolean值,返回的就是这个标志域的值。也就是说,其实interrupt()方法除了把这个标志域设定为true之后,其他什么也没干了。这就解释了上例中的线程为什么不能被正确地中断。所以,我们可以把SimpleThread类的run()方法改写成下面这个样子:
再运行测试程序,就会发现,2秒后线程会停止打印,它确实是被中断了。
有时候,我们不仅仅想要中断一个像上面这样重复着做同一件事的线程。很多情况下,我们需要的是中断一个休眠中的线程。毕竟开始因为某种需要,让一个线程休眠一段很长的时间,后来你就后悔了,想中断它的休眠。这个时候,interrupt()方法就又有用武之地了。
比如,我们有个LongTimeSleepThread线程类,他的工作就是睡之前说:“我要睡了,千万别打搅我”,然后睡两秒钟,醒来之后就说:“我醒来了”。注意到,在他睡之前,他只是告诉别人:不要打搅我。但是他并不能保证别人真的不会去打搅他。所以一旦他被人打搅,就会抱怨地说一句:“有人打搅我了”。
因为t并没有被打扰,所以输出结果是:
我们更改一下测试类,让t在睡眠过程中被打搅:
这个时候的输出结果就变成了:
一个线程在休眠,不能保证不被中断和一个人睡觉,不能保证不被打搅是一个道理。这就是为什么Thread的sleep()方法会可能抛出一个InterruptedException的原因。同样地,Thread类的join()方法,Object类的wait()方法,都可能抛出InterruptedException。
所以,如果想要中断一个正在sleep或者join或者wait的线程,调用线程的interrupt()方法即可,然后把在中断后需要的操作写进catch语句块里。
线程的状态
在了解如何中断线程之前,先应该弄清楚线程的几种状态:新建状态(New):一个新的线程在被创建之后,在运行(或阻塞)之前的状态。
就绪状态(Runnable):当一个线程只要拥有CPU时间片就能运行的时候,这个线程就处于就绪状态。
阻塞状态(Blocked):线程还没有死亡,但是由于一些原因不能继续运行,但是还能回到就绪状态。
死亡状态(Dead):当一个线程的任务已经完成,即run方法已经正确返回,或者被中断,这个线程就处于死亡状态。
引起阻塞的原因
一个线程可能会因为以下几个原因进入阻塞状态:调用了Thread.sleep()方法;
调用了wait(),线程被挂起;
线程在等待其他操作完成。例如正在等待输入;
线程在等待其他线程持有的锁。
interrupt()方法
说到中断,就会想到interrupt()方法,文档中对这个方法的功能描述是:Interrupts this thread.
但是,这个方法能不能真的轻而易举地中断一个线程呢?我们可以用下面的代码进行测试:
public class SimpleThread extends Thread { @Override public void run() { while(true) { System.out.println("I am doing my job!"); } }
SimpleThread st = new SimpleThread(); st.start(); try { Thread.sleep(2000); st.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); }
impleThread继承了Thread,它的run()方法就是不断地将“i am doing my job!”这句话打印到控制台。在测试类的主方法中启动了一个这样的线程,并且主线程打算在2秒之后中断这个线程。可是运行的结果并不是我们预期的那样:控制台还是不断地在打印“I am doing my job!”。
看来,interrupt()方法并没有成功的中断我们的线程。那么interrupt()方法到底做了些什么呢?
为了便于理解,其实可以这样来类比(注意,只是类比,实际情况并不完全是这样):Thread类中有一个boolean的标志域用来表示线程是否需要被中断,默认是false。interrupt()方法被调用之后,这个标志域就变成了true。当然,Thread类有一个interrupted()方法返回一个boolean值,返回的就是这个标志域的值。也就是说,其实interrupt()方法除了把这个标志域设定为true之后,其他什么也没干了。这就解释了上例中的线程为什么不能被正确地中断。所以,我们可以把SimpleThread类的run()方法改写成下面这个样子:
@Override public void run() { while(!interrupted()) { System.out.println("I am doing my job!"); } }
再运行测试程序,就会发现,2秒后线程会停止打印,它确实是被中断了。
有时候,我们不仅仅想要中断一个像上面这样重复着做同一件事的线程。很多情况下,我们需要的是中断一个休眠中的线程。毕竟开始因为某种需要,让一个线程休眠一段很长的时间,后来你就后悔了,想中断它的休眠。这个时候,interrupt()方法就又有用武之地了。
比如,我们有个LongTimeSleepThread线程类,他的工作就是睡之前说:“我要睡了,千万别打搅我”,然后睡两秒钟,醒来之后就说:“我醒来了”。注意到,在他睡之前,他只是告诉别人:不要打搅我。但是他并不能保证别人真的不会去打搅他。所以一旦他被人打搅,就会抱怨地说一句:“有人打搅我了”。
/** * 一个在run方法中休眠2秒得线程类 * * @author PSJay * */ public class LongTimeSleepThread extends Thread { @Override public void run() { System.out.println("I want to sleep. Don't bother me."); try { sleep(2000); } catch (InterruptedException e) { System.out.println("somebody bothered me."); } System.out.println("I wake up."); } }
public class Test { public static void main(String[] args) { LongTimeSleepThread t = new LongTimeSleepThread(); t.start(); } }
因为t并没有被打扰,所以输出结果是:
I want to sleep. Don't bother me. I wake up.[/code]
我们更改一下测试类,让t在睡眠过程中被打搅:
public class Test { public static void main(String[] args) { LongTimeSleepThread t = new LongTimeSleepThread(); t.start(); t.interrupt(); } }
这个时候的输出结果就变成了:
I want to sleep. Don't bother me. somebody bothered me. I wake up.[/code]
一个线程在休眠,不能保证不被中断和一个人睡觉,不能保证不被打搅是一个道理。这就是为什么Thread的sleep()方法会可能抛出一个InterruptedException的原因。同样地,Thread类的join()方法,Object类的wait()方法,都可能抛出InterruptedException。
所以,如果想要中断一个正在sleep或者join或者wait的线程,调用线程的interrupt()方法即可,然后把在中断后需要的操作写进catch语句块里。
相关文章推荐
- Java多线程与并发(四)之中断线程
- Java并发总结(三):中断线程
- java多线程--线程中断
- 【java多线程与并发库】---传统java多线程<2> 线程创建方式
- Android多线程研究(7)——Java5中的线程并发库
- 【Java 语言】Java 多线程 一 ( 线程启动 | 线程中断 )
- java 多线程基础之二:线程的中断(interrupt)
- Java并发之线程中断
- java多线程与并发之java线程简介(四)
- 并发基础(八) java线程的中断机制
- Java 多线程编程之一 进程与线程,并发和并行的区别:吃馒头的比喻
- Java 多线程 并发 锁 Java线程面试题 Top 50
- Java多线程与并发库高级应用-java5线程并发库
- java并发-多线程之线程的创建(2)
- 深入理解Java并发机制(5)--线程、中断、Runnable、Callable、Future
- Java并发01:进程、线程、并发、并行、多线程、线程安全、死锁、并发优缺点
- 【java多线程与并发库】---传统java多线程<2> 线程创建方式
- Android多线程研究(7)——Java5中的线程并发库
- Java挑战高并发(2):线程中断
- Java多线程与线程并发库高级应用笔记2版