Java 为什么在阻塞调用之前过早设置中断状态会导致无限循环?
我正在读“实践中的并发”,在第6章“对中断的响应”中,它说 过早设置中断状态可能会导致无限循环,因为大多数可中断的阻塞方法会在进入时检查中断状态,如果设置了中断,则会立即抛出InterruptedException。(可中断方法通常在阻塞或执行任何重要工作之前对中断进行轮询,以便在阻塞或执行任何重要工作之前对中断作出响应,以便尽可能对中断作出响应)Java 为什么在阻塞调用之前过早设置中断状态会导致无限循环?,java,multithreading,Java,Multithreading,我正在读“实践中的并发”,在第6章“对中断的响应”中,它说 过早设置中断状态可能会导致无限循环,因为大多数可中断的阻塞方法会在进入时检查中断状态,如果设置了中断,则会立即抛出InterruptedException。(可中断方法通常在阻塞或执行任何重要工作之前对中断进行轮询,以便在阻塞或执行任何重要工作之前对中断作出响应,以便尽可能对中断作出响应) 公共任务getNextTask(阻塞队列){ 布尔值=假; 试一试{ while(true){ 试一试{ 返回队列。take(); }捕捉(中断异常
公共任务getNextTask(阻塞队列){
布尔值=假;
试一试{
while(true){
试一试{
返回队列。take();
}捕捉(中断异常e){
中断=真;
//失败并重试
}
}
}最后{
如果(中断)
Thread.currentThread().interrupt();
}
}
假设代码是
public Task getNextTask(BlockingQueue<task> queue){
boolean interrupted=false;
while(true){
/*i get this part that before the take() function threads interrupted status is checked*/
return queue.take();
}catch(InterruptedException e){
interrupted=true;
Thread.currentThread().interrupt();
}
}//end of while
}
公共任务getNextTask(阻塞队列){
布尔值=假;
while(true){
/*在检查take()函数线程的中断状态之前,我得到了这一部分*/
返回队列。take();
}捕捉(中断异常e){
中断=真;
Thread.currentThread().interrupt();
}
}//结束
}
现在,为什么最后一个函数会导致无限循环,因为我已经将threrad的中断状态设置回false,根据我的理解,在阻塞调用轮询线程的中断状态期间,它将检查它是否被设置,它将发现它为false,然后继续调用。那么无限循环在哪里呢op进入画面?将抛出一个
中断异常
,因为take()
方法检查中断。此检查/抛出通常采用以下形式:
if (Thread.currentThread.interrupted()) { // Checks and clears the interrupted flag.
throw new InterruptedException();
}
然后捕获InterruptedException
,恢复中断标志,并再次调用take()
。这将检查中断,发现线程已中断,然后抛出InterruptedException
然后捕获InterruptedException
,恢复中断标志,并再次调用take()
。这将检查中断,发现线程已中断,然后抛出InterruptedException
然后捕获InterruptedException
,恢复中断标志,并再次调用take()
。这将检查中断,发现线程已中断,然后抛出InterruptedException
等等。第二个代码甚至不会编译。如果
队列中出现队列,那么第一个代码段将落入无限循环。take
总是被中断,并且永远不会返回任何内容。@michalk你能提供一个更清楚的例子来解释为什么吗?如果调用了重置,那么检查中断的代码为什么会抛出InterruptedException beca现在使用它的中断状态已被清除?我已将“重置”改写为“还原”。因此,一旦线程被中断并抛出InterruptedException,它的中断标志将被清除?因此,在上面编写的代码中,如果我将“if(Thread.currentThread.interrupted()”,则在catch块中,它将变成false?@GaganSingh不一定。interrupted标志和interrupted exception是表示中断的正交机制。Thread.interrupted()
清除中断标志,Thread.isInterrupted()
不。但是interrupted()
倾向于在抛出异常之前立即使用,以便清除标志,使其看起来不会“双重中断”(这不是一件事;对于处理异常的人来说,这只是一种令人困惑的状态)。
if (Thread.currentThread.interrupted()) { // Checks and clears the interrupted flag.
throw new InterruptedException();
}