用interrupt()中断Java线程
假如我们有一个任务如下,交给一个Java线程来执行,如何才能保证调用interrupt()来中断它呢?
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- //死循环执行打印"I am running!" 和做消耗时间的浮点计算
- while (true) {
- System.out.println("I am running!");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- //给线程调度器可以切换到其它进程的信号
- Thread.yield();
- }
- }
- }
- public class InterruptTaskTest {
- public static void main(String[] args) throws Exception{
- //将任务交给一个线程执行
- Thread t = new Thread(new ATask());
- t.start();
- //运行一断时间中断线程
- Thread.sleep(100);
- System.out.println("****************************");
- System.out.println("Interrupted Thread!");
- System.out.println("****************************");
- t.interrupt();
- }
- }
运行这个程序,我们发现调用interrupt()后,程序仍在运行,如果不强制结束,程序将一直运行下去,如下所示:
- ......
- I am running!
- I am running!
- I am running!
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- ....
虽然中断发生了,但线程仍然在进行,离开线程有两种常用的方法:
抛出InterruptedException和用Thread.interrupted()检查是否发生中断,下面分别看一下这两种方法:
1.在阻塞操作时如Thread.sleep()时被中断会抛出InterruptedException(注意,进行不能中断的IO操作而阻塞和要获得对象的锁调用对象的synchronized方法而阻塞时不会抛出InterruptedException)
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- //死循环执行打印"I am running!" 和做消耗时间的浮点计算
- try {
- while (true) {
- System.out.println("I am running!");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- //休眠一断时间,中断时会抛出InterruptedException
- Thread.sleep(50);
- }
- } catch (InterruptedException e) {
- System.out.println("ATask.run() interrupted!");
- }
- }
- }
程序运行结果如下:
- I am running!
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- ATask.run() interrupted!
可以看到中断任务时让任务抛出InterruptedException来离开任务.
2.Thread.interrupted()检查是否发生中断.Thread.interrupted()能告诉你线程是否发生中断,并将清除中断状态标记,所以程序不会两次通知你线程发生了中断.
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- //检查程序是否发生中断
- while (!Thread.interrupted()) {
- System.out.println("I am running!");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- }
- System.out.println("ATask.run() interrupted!");
- }
- }
程序运行结果如下:
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- ATask.run() interrupted!
我们可结合使用两种方法来达到可以通过interrupt()中断线程.请看下面例子:
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- try {
- //检查程序是否发生中断
- while (!Thread.interrupted()) {
- System.out.println("I am running!");
- //point1 before sleep
- Thread.sleep(20);
- //point2 after sleep
- System.out.println("Calculating");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- }
- } catch (InterruptedException e) {
- System.out.println("Exiting by Exception");
- }
- System.out.println("ATask.run() interrupted!");
- }
- }
在point1之前处point2之后发生中断会产生两种不同的结果,可以通过修改InterruptTaskTest main()里的Thread.sleep()的时间来达到在point1之前产生中断或在point2之后产生中断.
如果在point1之前发生中断,程序会在调用Thread.sleep()时抛出InterruptedException从而结束线程.这和在Thread.sleep()时被中断是一样的效果.程序运行结果可能如下:
- I am running!
- Calculating
- I am running!
- Calculating
- I am running!
- Calculating
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- Exiting by Exception
- ATask.run() interrupted!
如果在point2之后发生中断,线程会继续执行到下一次while判断中断状态时.程序运行结果可能如下:
- I am running!
- Calculating
- I am running!
- Calculating
- I am running!
- Calculating
- ****************************
- Interrupted Thread!
- ****************************
- ATask.run() interrupted!
在Java多线程中,线程的状态有 NEW, Runnable, Blocked, Waiting, Timed_Waiting, Terminated. 这是java虚拟机下的线程状态,与操作系统下的线程状态略有不同。线程状态以枚举类型定义在Thread.State中,并且当前线程可以通过getState()方法获取当前线程的状态。Runnable其实可以有两种状态,一种是获得了cpu,这在运行,这里把它表示为Running,另一种在队列中,等待调度。
这些状态之间的转化关系可以通过下面的转化图表示:
有些过程没有写,不然太乱了。
这里重点说一下stop()以及interrupt。
对于stop()方法,直接终止线程,释放线程所获的资源,但是在释放过程中会造成对象状态不一致,从而使程序进入未知的境地,已经很久不推荐使用了。可以通过设定标志位来检测线程终止状态,使线程自动终止。简略实现如下:
boolean stop = false;
public void run(){
while(!stop){
}
}
在需要终止线程的地方把stop设置为true即可。
interrupt方法好多初学者会感到困惑,发现一些情况下并不能终止线程。在JavaAPI中有对此详细的说明:
如果线程在调用 Object
类的 wait()
、wait(long)
或 wait(long, int)
方法,或者该类的join()
、join(long)
、join(long, int)
、sleep(long)
或 sleep(long, int)
方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException
。
如果该线程在可中断的通道
上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个
ClosedByInterruptException
。
因此,可以看出,interrupt之后作用到wait() join() 已经sleep()上。 2014阿里巴巴笔试题的附加题中对这个知识进行了终点考核,其代码如下:
- public class TestInterrupt {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Thread thread1 = new Thread(){
- public void run(){
- try{
- long time = System.currentTimeMillis();
- while(System.currentTimeMillis()-time<2000){
- }
- System.out.println("A1");
- }
- catch(Exception e)
- {
- System.out.println("B1");
- }
- }
- };
- thread1.start();
- thread1.interrupt();
- //在线程sleep状态下进行中断
- Thread thread2 = new Thread(){
- public void run(){
- try {
- this.sleep(2000);
- System.out.println("A2");
- } catch (Exception e) {
- // TODO Auto-generated catch block
- System.out.println("B2");
- }
- }
- };
- thread2.start();
- thread2.interrupt();
- //在线程wait状态下进行中断,其中wait()没有在同步块中
- Thread thread3 = new Thread(){
- public void run(){
- try {
- this.wait(2000);
- System.out.println("A3");
- } catch (Exception e) {
- // TODO Auto-generated catch block
- System.out.println("B3");
- }
- }
- };
- thread3.start();
- thread3.interrupt();
- //在线程wait状态下进行中断,其中wait()在同步块中
- Thread thread4 = new Thread(){
- public void run(){
- try {
- synchronized(this){
- this.wait(2000);
- System.out.println("A4");}
- } catch (Exception e) {
- // TODO Auto-generated catch block
- System.out.println("B4");
- }
- }
- };
- thread4.start();
- thread4.interrupt();
- try{
- thread4.start();
- System.out.println("A5");
- }
- catch(Exception e)
- {
- System.out.println("B5");
- System.out.println(e.toString());
- }
- }
- }
我们可以运行,发下运行结果如下(不考虑执行顺序):
A1
B2
B3
B4
B5 //这个是由于一个thread,不能start两次引起的。。和interrupt无关
用interrupt()中断Java线程的更多相关文章
- Java Thread.interrupt 害人! 中断JAVA线程(zz)
http://www.blogjava.net/jinfeng_wang/archive/2012/04/22/196477.html#376322 ————————————————————————— ...
- 一文搞懂 Java 线程中断
在之前的一文<如何"优雅"地终止一个线程>中详细说明了 stop 终止线程的坏处及如何优雅地终止线程,那么还有别的可以终止线程的方法吗?答案是肯定的,它就是我们今天要分 ...
- Java - 线程Join与interrupt
Java多线程系列--“基础篇”08之 join() 概要 本章,会对Thread中join()方法进行介绍.涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_ ...
- java线程中断
public void Thread.interrupt() // 无返回值 public boolean Thread.isInterrupted() // 有返回值 public static b ...
- Java 线程宝典
此文 为垃圾文 本人复习用的 emmm 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程 并行与并发: 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时. 并发:通过cpu ...
- java线程高并发编程
java线程具体解释及高并发编程庖丁解牛 线程概述: 祖宗: 说起java高并发编程,就不得不提起一位老先生Doug Lea,这位老先生可不得了.看看百度百科对他的评价,一点也不为过: 假设IT的历史 ...
- 【Java 线程的深入研究2】常用函数说明
①sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) ②join():指等待t线程终止. 使用方式. join是Thread类的一个方法,启动线程后直接调用, ...
- Thread的中断机制(interrupt),循环线程停止的方法
一.中断原理 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个 ...
- 理解java线程的中断(interrupt)
一个线程在未正常结束之前, 被强制终止是很危险的事情. 因为它可能带来完全预料不到的严重后果比如会带着自己所持有的锁而永远的休眠,迟迟不归还锁等. 所以你看到Thread.suspend, Threa ...
随机推荐
- ANY和SOME 运算符
在SQL中ANY和SOME是同义词,所以下面介绍的时候只使用ANY,SOME的用法和功能和ANY一模一样.和IN运算符不同,ANY必须和其他的比较运算符共同使用,而且必须将比较运算符放在ANY 关键字 ...
- [BZOJ4004][JLOI2015]装备购买(贪心+线性基)
求最小权极大线性无关组. 先将所有向量按权值排序,从小到大依次判断,若能被前面已选向量线性表出则不选,这样一定最优. 据说是用拟阵来证明,但感性理解一下感觉比较显然,首先这样个数一定是最多的,其次对于 ...
- bzoj 1783: [Usaco2010 Jan]Taking Turns
1783: [Usaco2010 Jan]Taking Turns Description Farmer John has invented a new way of feeding his cows ...
- codevs 1962 马棚问题--序列型DP
1962 马棚问题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 每天,小明和他的马外出,然后他们一边跑一边玩耍.当他们结束 ...
- opensue fstab故障恢复
date: 20140505 author: Jin 故障背景: 早上启动本本 无法启动,报错信息(几个关键) WARNING:Failed to connect to lvmetad: No suc ...
- Linux虚拟化技术KVM、QEMU与libvirt的关系(转)
说明:个人理解,KVM是内核虚拟化技术,而内核是不能使用在界面上使用的,那么此时QEMU提供了用户级别的使用界面,相互辅助.当然,单独使用QEMU也是可以实现一整套虚拟机,不过QEMU+KVM基本是标 ...
- Understanding how SQL Server executes a query
https://www.codeproject.com/Articles/630346/Understanding-how-SQL-Server-executes-a-query https://ww ...
- [Bug]Object reference not set to an instance of an object.
引言 今天在客户这儿,由一个问题导致,需求的变化,不得不修改代码,在记录日志中出现该问题. 原因 通过id查找相关信息,没有判断是否为null,集合是否有数据. Object reference no ...
- iOS开发利器-CocoaPods安装和使用教程
新博客http://www.liuchendi.com 开发iOS项目时肯定会用到许多第三方项目,比如说:ASIHttprequest,JSONKit等等,一些类库可能又关联着其他类库,如果超过一定的 ...
- andriod获得textView的值设置textView的text
TextView pTextView=(TextView)findViewById(R.id.textView2);String str=pTextView.getText().toString(); ...