java中断是一种中断机制 如果我们写的线程没有对中断请求进行响应那么线程是无法被中断的。(这里说的是线程代码是指在子线程中运行的所有方法代码。当然第一个方法就是Thread的run方法)
示例代码:
public class ThreadInterruptTest {
//任务的阻塞队列
BlockingQueue<Runnable> blockingQueue;
public static void main(String[] args) {
ThreadInterruptTest test = new ThreadInterruptTest();
test.init();
}
/**
*<p>TODO(概括性描述)</p><br/>
*<p>TODO(详细描述)</p>
* @since 2.6
* @author liulp
*/
private void init() {
// TODO Auto-generated method stub
//初始化阻塞队列
blockingQueue = new ArrayBlockingQueue<Runnable>(20);
Thread t = new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
//从队列中取任务 然后执行 直到执行完任务
while (true) {
MyRunnable run = (MyRunnable) blockingQueue.poll();
if (run != null) {
System.out.println("task "+run.i+" start");
//执行任务
run.run();
} else {
break;
}
}
}
};
//添加10个任务
for (int i = 1; i <= 10; i++) {
try {
blockingQueue.put(new MyRunnable(i));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//启动线程
t.start();
//中断线程
t.interrupt();
//继续添加任务
blockingQueue.add(new MyRunnable(11));
}
class MyRunnable implements Runnable {
int i;
/**
*
*/
public MyRunnable(int i) {
// TODO Auto-generated constructor stub
this.i = i;
}
@Override
public void run() {
int m = 0;
int a = 0;
//消耗CP时间
for (; m < Integer.MAX_VALUE; m++) {
a++;
}
System.out.println("Task " + i + " end");
}
}
}
运行结果:
task 1 start
Task 1 end
task 2 start
Task 2 end
task 3 start
Task 3 end
task 4 start
Task 4 end
task 5 start
Task 5 end
task 6 start
Task 6 end
task 7 start
Task 7 end
task 8 start
Task 8 end
task 9 start
Task 9 end
task 10 start
Task 10 end
task 11 start
Task 11 end
可以看到 虽然我们调用了线程的中断但是所有的任务都执行完毕了,甚至我们在调用中断后添加的任务也执行了。
那么我们应该怎么样中断任务呢?
我们知道java的线程中断时一种写作机制,并不是调用线程的中断方法 就可以中断线程,而是需要任务的执行者来响应中断才可以。
我们稍微修改下MyRunnable的run方法来响应中断。
public void run() {
//如果有中断请求
if(Thread.interrupted()){
//直接reutrn掉
return;
}
int m = 0;
int a = 0;
//消耗CP时间
for (; m < Integer.MAX_VALUE; m++) {
a++;
}
System.out.println("Task " + i + " end");
}
运行结果如下:
task 1 start
task 2 start
Task 2 end
task 3 start
Task 3 end
task 4 start
Task 4 end
task 5 start
Task 5 end
task 6 start
Task 6 end
task 7 start
Task 7 end
task 8 start
Task 8 end
task 9 start
Task 9 end
task 10 start
Task 10 end
task 11 start
Task 11 end
哦看起来好像没有什么变化,所有的任务都打印了,但是仔细看你会发现少了一句
task 1 end
这说明task 1的run方法没有执行完 而是return了。
我们通过在run方法中检查中断状态中断了task 1的执行,但是其他的任务并没有被中断,这是因为调用thread.interrupted()会恢复状态中断,在线程中第二次调用
interrupted() 就返回false了,如果我们想中断所有的任务怎么办呢?那只有想办法让线程完全终止,我们可以通过跑车一个Error 或是RuntimeExcepton终止线程的
执行,我们再次修改 MyRunnable的run方法:
@Override
public void run() {
//如果有中断请求
if(Thread.interrupted()){
// Error e =new Error("die");
RuntimeException e = new RuntimeException("die");
throw(e);
}
int m = 0;
int a = 0;
//消耗CP时间
for (; m < Integer.MAX_VALUE; m++) {
a++;
}
System.out.println("Task " + i + " end");
}
运行结果:
task 1 start
Exception in thread "Thread-0" java.lang.RuntimeException: die
at com.popo.test.thread.ThreadInterruptTest$MyRunnable.run(ThreadInterruptTest.java:103)
at com.popo.test.thread.ThreadInterruptTest$1.run(ThreadInterruptTest.java:56)
线程完全被终止了,不过如果我们在Thread.run()方法中捕获RuntimeException线程也是不会被终止的,有兴趣的可以实现下。
当然我们如果在执行任务队列是不应该中断其他任务的执行的,除非调用者有显示的调用(比如Executes.shutDownNow()方法 就是终止所有未完成的任务)
最后加上一段 Thread.interrupt()方法的注释
Posts an interrupt request to this Thread
. The behavior depends on the state of this Thread
:
Thread
s blocked in one ofObject
'swait()
methods or one ofThread
'sjoin()
orsleep()
methods will be woken up, their interrupt status will be cleared, and they receive anInterruptedException
.Thread
s blocked in an I/O operation of anjava.nio.channels.InterruptibleChannel
will have their interrupt status set and receive anjava.nio.channels.ClosedByInterruptException
. Also, the channel will be closed.Thread
s blocked in ajava.nio.channels.Selector
will have their interrupt status set and return immediately. They don't receive an exception in this case.
第三种情况会设置中断状态 并且selector马上返回但是不会收到异常。这种异常处理应该需要程序员自己去检查中断状态来响应中断。