如何解决Java并发-中断政策
我正在阅读Java Concurrency in Practice 。在章节“中断策略”中
取消和关闭
提到了
除非任务被明确设计为在具有特定中断策略的服务中运行,否则该任务不应假设其执行线程的中断策略有任何意义。任务是将中断解释为取消还是对中断采取其他措施,都应注意保留执行线程的中断状态。如果它不打算将InterruptedException传播给调用者,则应在捕获InterruptionException之后恢复中断状态: Thread.currentThread()。interrupt()
因此,我尝试使用列表示例进行理解。但是我对输出感到困惑。
PrimeProducer
public class CorrectPrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
public CorrectPrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+" interrupt status in producer:" + Thread.currentThread().isInterrupted());
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted()) {
queue.put(p = p.nextProbablePrime());
}
} catch (InterruptedException e) {
/* Allow thread to exit */
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().getName()+" interrupt status in producer catch:" + Thread.currentThread().isInterrupted());
}
}
}
主要方法##
public static void main(String[] args) throws InterruptedException {
BlockingQueue<BigInteger> primes = new LinkedBlockingQueue<>();
CorrectPrimeProducer generator = new CorrectPrimeProducer(primes);
generator.start();
try {
while (needMorePrimes()) {
consume(primes.take());
}
} finally {
generator.interrupt();
}
TimeUnit.SECONDS.sleep(5);
System.out.println(generator.getName()+" interrupt status in main:"+generator.isInterrupted());
}
//do something
private static void consume(BigInteger take) {
System.out.println(take);
}
private static int counter = 1;
private static boolean needMorePrimes() {
counter++;
if(counter == 10){
// after counter reaches 10 return false
return false;
}
return true;
}
输出:
// when TimeUnit.SECONDS.sleep(5); in main class is not commented
Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in producer catch:true
Thread-0 interrupt status in main:false
//When TimeUnit.SECONDS.sleep(5); in main class is commented
Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in main:true
Thread-0 interrupt status in producer catch:true
问题
-
只需在主类的主线程中添加TimeUnit.SECONDS.sleep(5)。正在执行的线程(即生成器)的中断状态正在重置。如果我注释TimeUnit.SECONDS.sleep(5)方法,则在这种情况下将保留中断状态。为什么会这样?如何发生?
-
在书中提到线程仅应由其所有者中断。在上面的示例中,谁是所有者?我认为它的主要方法是线程。
解决方法
只需在主类的主线程中添加TimeUnit.SECONDS.sleep(5)。正在执行的线程(即生成器)的中断状态正在重置。如果我注释TimeUnit.SECONDS.sleep(5)方法,则在这种情况下将保留中断状态。为什么会这样?如何发生?
您在主线程和CorrectPrimeProducer
之间没有使用任何同步机制(除了阻塞队列),因此当主线程打印状态时-CorrectPrimeProducer
可能尚未保留中断状态(通过执行catch
块指令),您将得到false
作为结果。
将sleep
添加到主Thread
时,您通过在主线程尝试之前调用CorrectPrimeProducer
块指令来增加catch
线程保留中断状态的可能性打印它的状态。这就是为什么它打印true
的原因。
在书中提到线程仅应由其所有者中断。在上面的示例中,谁是所有者?我认为它的主要方法是线程。
在这种情况下,您是CorrectPrimeProducer
线程的所有者(所有者是创建线程的代码),因此您可以决定中断的含义。例如,如果它被中断,您可以重新创建它(例如,默认情况下,来自Java线程池的Thread
s会发生这种情况。)
通过添加TimeUnit.SECONDS.sleep(5)
,您将为线程终止提供足够的时间。
当线程终止时,其中断标志被清除。
这没有在规范中记录,但这就是发生的情况。例如参见this bug report:
这里没有违反任何规范,因此我提出了增强请求而不是错误。可以说,缺乏规范是一个错误-我们确实有意指定“终止后的中断无需影响”,以处理中断状态存储在VM中且线程终止后不再存在的事实。但是,我们忽略了在Thread.isInterrupted规范中反映这一点。
在没有多余的sleep
的情况下,我怀疑理论上您可以同时看到true
和false
的中断状态,因为存在竞争状况,但是您看到{{ 1}}得益于线程调度。在抛出异常与在catch块中恢复中断状态之间,中断状态为假的时间窗口非常小。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。