Java线程中断机制-如何中断线程
介绍:
对于线程一共分为五个状态:新建状态,就绪状态,阻塞状态,运行状态,死亡状态,有时候把阻塞状态又分为同步阻塞和等待阻塞。
有时想让主线程启动的一个子线程结束运行,我们就需要让这个子线程中断,不再继续执行。线程是有中断机制的,我们可以对每个线程进行中断标记,注意只是标记,中断与否还是虚拟机自己的事情,虚拟机自己家的事情,我们也就说说,不能实际操作控制他家。java中的Thread类是一个对线程进行操作的类,提供了中断线程的方法interrupt(),在API中是这么定义的(中文的翻译可能不准确)。
在Thread中其实还有一个stop()方法也是中断线程的方法,但是这个方法太粗鲁了,人家好好的线程正在运行,只要调用了stop()方法,线程就会中断,不管是在进行什么操作。这个方法已经被废弃,他的执行会带来一些不可确定的状况。
线程可以调用中断自己的方法interrupt()方法,但是中断也是有条件的,在线程调用interrupt()方法的时候虚拟机会在此线程上标记一个标志(这个中断标志只是一个布尔类型的变量),代表这个线程可能被中断,在后面的中断操作也是根据这个中断标志执行的。可以说interrupt()方法是一种友好的方法,总是和虚拟机商量着来。如果一个线程处于了阻塞状态(如线程调用了sleep()、join()、wait()、以及可中断的通道上的 I/O 操作方法后可进入阻塞状态),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法(sleep()、join()、wait()及可中断的通道上的
I/O 操作方法)调用处抛出InterruptedException异常,并且在抛出异常后立即将线程的中断标示位清除,即重新设置为false。抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。
线程的一些状态都可能影响到这个中断标记从而结束中断。下面这个例子验证中断标志被除掉的说法
package demo_thread;
public class Interrupt {
public static void main(String[] args) {
A a = new A();
Thread t1 = new Thread(a);
t1.start();
t1.interrupt();
System.out.println("执行睡眠之前1:"+t1.isInterrupted());
try {
System.out.println("执行睡眠之前2:"+t1.isInterrupted());
t1.sleep(1000);//线程进入阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("执行睡眠之后:"+t1.isInterrupted());
}
}
}
class A implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread());
}
}
在main方法中创建一个线程,线程中重写的run()方法输出线程号,只是一个显示分隔,具体看在执行让线程阻塞方法之前和之后线程的中断标记。isInterrupted()方法是判断线程是否执行中断的方法,就是判断中断标记是否存在的方法。
输出:
执行睡眠之前1:true
执行睡眠之前2:true
Thread[Thread-0,5,main]
执行睡眠之后:false
可以看到只要执行了sleep()方法,线程的中断标记就会被清除。分别调用执行了join()、wait()方法,可以看到他们的共同点都是需要捕获一个InterruptedException,在调用join()方法的时候得到了和sleep()方法一样的输出结果,但是在调用wait()方法的时候,虽然在后面调用notify()方法,但是是否获得执行权限还是无法预料的。
中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断,中断或者不中断。某些线程非常重要,以至于它们应该不理会中断,而是在处理完抛出的异常之后继续执行,但是更普遍的情况是,一个线程将把中断看作一个终止请求。
两个很像的方法的区别:
interrupted():测试当前线程是否中断。 该方法可以清除线程的中断状态 。换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false(除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。
isInterrupted():测试这个线程是否被中断。线程的中断状态不受此方法的影响。
如何中断线程:
接下来看请求中断之后发生的事情:在网上看到一个例子
package demo_thread;
public class Interrupt {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();//请求中断MyThread线程
} catch (Exception e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
}
class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("should be stopped and exit");
break;
}
System.out.println("i=" + (i + 1));
}
//尽管线程被中断,但并没有结束运行。这行代码还是会被执行
System.out.println("this line is also executed. thread does not stopped");
}
}
在文章的开头处已经说了,线程执行中断方法,只是给线程一个中断标记,是否中断是他自己的事
其中一次的输出:
……
i=75722
end!
should be stopped and exit
this line is also executed. thread does not stopped
由于线程执行了sleep()方法,进入阻塞状态,所以在从阻塞状态从新回到运行状态的时候,发现自己已经有了中断标记,执行if中的语句,线程的睡眠和执行总是和计算机内部有关系,所以每次输出的结束数字总是不一样的。
通过输出结果我们发现一个很重要的问题,我们要的是线程的中断,也就是关于线程的方法需要停止执行,但是在循环外面的输出语句也执行了,这个中断只是中断了循环的执行。
那么我们应该怎么中断线程呢?利用线程中断异常就是一个很好的办法,既然是异常,通常异常可以中断线程的运行,使程序挂掉,我们自己抛出一个异常让线程中断
class MyThread extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("should be stopped and exit");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
System.out.println("this line cannot be executed. cause thread throws exception");//这行语句不会被执行!!!
} catch (InterruptedException e) {
System.out.println("catch interrupted exception");
e.printStackTrace();
}
}
}
输出:
……
i=131892
should be stopped and exit
end!
但是通过抛出异常也带来了问题,我们不能通过抛出异常来处理问题,还需要在捕获异常的代码中加上处理的语句,例如保存用户的操作等等,让这次中断看起来是很正常的中断。
我们还可以通过让程序主动抛出异常,在线程阻塞的时候,执行中断操作,抛出异常,在循环中循环打印当前时间,
package demo_thread; import java.text.SimpleDateFormat;
import java.util.Date; public class SleepInterruptTest {
public static void main(String[] args) {
SleepThread t1 = new SleepThread();
t1.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) { e.printStackTrace();
}
t1.interrupt();//主动打断线程,使SleepThread线程抛出异常
} }
class SleepThread extends Thread{
public void run(){
while(true){
try{
SimpleDateFormat sim = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
System.out.println(sim.format(new Date()));
sleep(1000);
}
catch(InterruptedException e){
System.out.println("线程中断");
return;
}
}
}
}
输出:
2017年10月14日 10:40:01
2017年10月14日 10:40:02
2017年10月14日 10:40:03
2017年10月14日 10:40:04
2017年10月14日 10:40:05
线程中断
参考:http://www.cnblogs.com/hapjin/p/5450779.html
Java线程中断机制-如何中断线程的更多相关文章
- Java线程监控及中断
我们系统中经常有耗费时间长的任务,但客户端往往需要马上得到回应.这时我们就可以如下步骤实现: 1.客户端发起请求执行任务(选定条件,下载报表): 2.首先将任务ID及开始时间,起始状态记录到数据库表中 ...
- Java多线程——中断机制
前言:在Java多线程中,中断一直围绕着我们,当我们阅读各种关于Java多线程的资料.书籍时,“中断”一词总是会出现,笔者对其的理解也是朦朦胧胧,因此非常有必要搞清楚Java多线程的中断机制. 1.J ...
- java 线程中断机制
上一篇文章我们了解过了java有关线程的基本概念,有线程的属性,线程可能处于的状态,还有线程的两种创建的方式,最后还说了一个关键字synchronized,解决了高并发导致数据内容不一致问题,本篇文章 ...
- 《Java并发编程》之线程中断与终止线程运行
Java中启动一个线程很容易,通常情况下我们都是等到任务运行结束后让线程自行停止.但有时需要在任务正在运行时取消他们,使得线程快速结束.对此Java并没有提供任何机制.但是我们可以通过Java提供的线 ...
- java线程池和中断总结
目录 java线程池和中断总结 一. 线程池的使用 二. java中断机制 中断的处理 三. 线程间通信机制总结 java线程池和中断总结 本系列文是对自己学习多线程和平时使用过程中的知识梳理,不适合 ...
- Java编程的逻辑 (69) - 线程的中断
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- JAVA interrupte中断线程的真正用途
Java线程之中,一个线程的生命周期分为:初始.就绪.运行.阻塞以及结束.当然,其中也可以有四种状态,初始.就绪.运行以及结束. 一般而言,可能有三种原因引起阻塞:等待阻塞.同步阻塞以及其他阻塞(睡眠 ...
- java并发编程(一)线程状态 & 线程中断 & 线程间的协作
参考文章: Java线程的5种状态及切换:http://blog.csdn.net/pange1991/article/details/53860651 线程的5种状态: 1. 新建(NEW):新创建 ...
- 【Java面试】如何中断一个正在运行的线程?
一个去京东面试的工作了5年的粉丝来找我说: Mic老师,你说并发编程很重要,果然我今天又挂在一道并发编程的面试题上了. 我问他问题是什么,他说:"如何中断一个正在运行中的线程?". ...
随机推荐
- FineUIPro控件库深度解析
FineUIPro控件库 FineUIPro是一套基于jQuery的专业ASP.NET控件库,始于2008年的开源版FineUI控件库. 当年为了提升项目的开发效率,降低代码复杂度,减少对CSS和Ja ...
- Redis笔记1-redis的搭建和使用
1. Redis的安装 1.1. Redis的安装 Redis是c语言开发的. 安装redis需要c语言的编译环境.如果没有gcc需要在线安装.yum install gcc-c++ 安装步骤: ...
- MFC: 获得关机消息;阻止Windows关机
WM_QUERYENDSESSION消息是Windows向你询问Windows能否关闭,WM_ENDSESSION消息表示提示你Windows即将关闭.故当应用程序退出时, WM_QUERYENDSE ...
- YPbPr 和 YCbCr的区别 .
这几天在做分量视频输入,涉及分量视频表示,接触到YPbPr和YCbCr的概念,发现不光自己的项目上,对这两个概念错乱,就是网上也充斥着大量错误的说法. 分量接口有两种名称YPbPr和YCbCr,这是两 ...
- AM335x(TQ335x)学习笔记——使用dtb方式启动内核
老式的u-boot使用ATAGS的方式启动linux内核,本文使用新式的dtb方式启动内核. 我使用的内核是linux-3.17.2版本,下面开始编译内核. (1) 解压内核 [php] view p ...
- java.sql.SQLException:Column count doesn't match value count at row 1
1.错误描述 java.sql.SQLException:Column count doesn't match value count at row 1 2.错误原因 在插入数据时,插入的字段 ...
- TypeError: Error #1034: 强制转换类型失败:无法将 "" 转换为 Array。
1.错误描述 TypeError: Error #1034: 强制转换类型失败:无法将 "" 转换为 Array. at mx.charts.series::LineSeries/ ...
- 2015 Multi-University Training Contest 4 Walk Out
Walk Out Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total S ...
- spring mvc和swagger整合
pom.xml 导入jar jar包 所属 备注 spring-core spring spring核心包 spring-expression spring spEl表达式 spring-beans ...
- GridView中添加行单击事件.md
[toc] 1.使用说明 1.方法来源 该方法主要参考StackOverflow上面的答案和下面这篇文章 http://www.codeproject.com/Articles/15677/Click ...