陷阱 - 捕获 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(); 
        }
    }
}