Interrupted exception vs isInterrupted in a while

2019-03-31 07:11发布

问题:

Assume that I have the following code:

while(!Thread.currentThread().isInterrupted()){  
    //do something   
    Thread.sleep(5000);  
}

Now Thread.sleep throws `InterruptedException so it should be like this:

while(!Thread.currentThread().isInterrupted()){  
   //do something   
   try{  
     Thread.sleep(5000);    
   } catch(InterruptedException e){  

   }
}

If I hit the catch will the while loop continue or do I need to do Thread.currentThread().interrupt()? If I do call this method, won't that also cause an InterruptedException? Otherwise how I got the exception in the first place?

Also if I have:

while (!Thread.currentThread().isInterrupted()){  
   //do something   
   callMethod();  
}  

private void callMethod(){  
   //do something  
   try {  
     Thread.sleep(5000);    
   } catch(InterruptedException e){  

   }
}

again will my while loop break?

回答1:

Actually your question is more about try - catch - finally than about multithreading.

1) If sleep throws an Exception, the catch block will execute and then the while loop continues.

2) You do the exact same thing as in 1)

To leave the while loop, do:

try{  
   while(!Thread.currentThread.isInterrupted){  
       //do something   
       Thread.sleep(5000);    
   }  
}
catch(InterruptedException e){  

}

In that case, if an Exception is thrown, the while loop is left and the catch block is executed.



回答2:

Thread.sleep() will clear the "interrupted status" before throwing InterruptedException. You need to call Thread.currentThread().interrupt() in the catch block, otherwise the while condition will most likely not succeed, because the thread will always be "not interrupted" when callMethod returns.

The exception is not caused by the interrupt() method, but by sleep() blocking on a thread that has been signaled as "interrupted". This is explained in more detail here. See also this answer.



回答3:

Calling interrupt on a thread does not in itself throw an exception. Sleeping or waiting while the interrupt flag is set is what causes InterruptedException to be thrown.

It is totally predictable what can throw InterruptedException, so that the thread being interrupted has control and it can choose how to respond. It's a checked exception so it's evident what throws it. It is not like ThreadDeath, which can be thrown anywhere.

When an InterruptedException is thrown the thread's interrupted status is reset. If you want to restore the thread's interrupted status, because you want to check the flag later and have it be true, call Thread.currentThread().interrupt() in order to set it.

Nothing out of the ordinary happens during interruption to change how instructions get processed. So if you choose to catch the InterruptedException in a loop and check the flag to get out, you will need to reset the flag:

while(!Thread.currentThread().isInterrupted()){  
   //do something   
   try{  
     Thread.sleep(5000);    
   } catch(InterruptedException e){  
        Thread.currentThread().interrupt();
   }
}

Alternatively you can use the InterruptedException to get out of the loop:

try {
    while (!Thread.currentThread().isInterrupted()) {
        // do something
        Thread.sleep(5000);
    }
} catch (InterruptedException e) {
    // flag value is not used here, but still good style
    Thread.currentThread().interrupt(); 
}

If this last snippet is the whole run method of the thread being interrupted, you can get by without setting the interrupted status again, but if you have components being used by other parts you don't want one badly-behaved part to squelch the interrupted flag so that other code in the thread is not aware of the interruption.