陷阱 - 捕獲 InterruptedException

正如已經在其他陷阱中指出的那樣,通過使用捕獲所有異常

try {
    // Some code
} catch (Exception) {
    // Some error handling
}

有很多不同的問題。但是一個特別的問題是它可能導致死鎖,因為它在編寫多執行緒應用程式時會破壞中斷系統。

如果你開始一個執行緒,你通常還需要能夠出於各種原因突然停止它。

Thread t = new Thread(new Runnable() {
    public void run() {
         while (true) {
             //Do something indefinetely
         }
    }
}

t.start();

//Do something else

// The thread should be canceld if it is still active. 
// A Better way to solve this is with a shared variable that is tested 
// regularily by the thread for a clean exit, but for this example we try to 
// forcibly interrupt this thread.
if (t.isAlive()) {
   t.interrupt();
   t.join();
}

//Continue with program

t.interrupt() 將在該執行緒中引發 InterruptedException,而不是用於關閉執行緒。但是如果 Thread 需要在完全停止之前清理一些資源呢?為此,它可以捕獲 InterruptedException 並進行一些清理。

 Thread t = new Thread(new Runnable() {
    public void run() {
        try {
            while (true) {
                //Do something indefinetely
            }
        } catch (InterruptedException ex) {
            //Do some quick cleanup

            // In this case a simple return would do. 
            // But if you are not 100% sure that the thread ends after 
            // catching the InterruptedException you will need to raise another 
            // one for the layers surrounding this code.                
            Thread.currentThread().interrupt(); 
        }
    }
}

但是如果你的程式碼中有一個 catch-all 表示式,那麼 InterruptedException 也會被它捕獲,並且中斷將不會繼續。在這種情況下會導致死鎖,因為父執行緒無限期地等待這個 thead 用 t.join() 停止。

 Thread t = new Thread(new Runnable() {
    public void run() {
        try {
            while (true) {
                try {
                    //Do something indefinetely
                }
                catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (InterruptedException ex) {
            // Dead code as the interrupt exception was already caught in
            // the inner try-catch           
            Thread.currentThread().interrupt(); 
        }
    }
}

因此最好單獨捕獲 Exceptions,但如果你堅持使用 catch-all,至少事先單獨捕獲 InterruptedException。

Thread t = new Thread(new Runnable() {
    public void run() {
        try {
            while (true) {
                try {
                    //Do something indefinetely
                } catch (InterruptedException ex) {
                    throw ex; //Send it up in the chain
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (InterruptedException ex) {
            // Some quick cleanup code 
    
            Thread.currentThread().interrupt(); 
        }
    }
}