正如我在线程中断中所写的,interrupt标志是消耗品,且其本身无法中断线程。正是该问题导致我的项目中一个子线程未按照预期退出。
问题描述
主线程启动两个子线程A和B。B为ScheduledExecutorService的定时任务,通过shundown方法可终止该任务。A线程依赖于B的定时任务所得结果,故通过阻塞队列来实现A-B的顺序执行。
主线程暴露出一个终止任务方法供使用者调用,B通过shundownNow方法终止,A通过interrupt设置中断标志,在A中死循环中通过isinterrupted方法判断跳出。
while (true) {
......业务代码
while(poll==null&&!Thread.currentThread().isInterrupted()) {
poll = message.poll(5, TimeUnit.SECONDS);//尝试获取B线程的执行结果
}
if(Thread.currentThread().isInterrupted()) {
System.out.println("完全跳出A");
break;
}
......业务代码
}
但在实际调用终止任务方法时,进程始终未退出,通过VisualVM监控虚拟机线程发现A线程在调用中断后并未退出。
疑惑之下,在主线程中加入打印语句,发现A线程在B线程退出20s后依然处于alive状态,更令我感觉困惑的事情是在终止任务中添加interrupt中断标志后,添加了一条打印isInterrupted(),查看中断标志,结果居然是false。
threadA.interrupt();
System.out.println("A线程:"+threadA.isInterrupted());
...
A线程:false
...
bug修复
正如我在线程中断的相关方法中所写的,interrupt标志是一个消耗品。在标志被sleep、wait响应后,标志位被重制为false。
而阻塞队列的poll方法正是可以响应interrupt标志的方法
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
既然如此,设置中断的方式不能正确被响应到,那还是通过设置类成员属性标志位来解决问题吧。
网友评论