我們知道很多類庫中的阻塞方法在拋出InterruptedException后會清除線程的中斷狀態(例如 sleep、 阻塞隊列的take),但是今天卻發現了一個特別奇怪的現象,先給出代碼:
public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { System.out.println("first interrupted!!!"); } System.out.println(Thread.currentThread().isInterrupted()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { System.out.println("second interrupted!!!"); } } }); executor.shutdownNow(); }
如果按照我的理解,調用shutdownNow后會給線程池中的工作者線程發出中斷請求,並在第一個睡眠的地方拋出 InterruptedException ,但是在拋出異常后這種中斷狀態就應該被清除了,所以第二次睡眠不應該失敗,但是結果卻是失敗的,本來以為是系統的原因,可是在linux下測試也是如此。
更令人不解的是如果我把第二次睡眠換成其他的阻塞方法(queue.take)那么就不會拋出異常,而是正常阻塞。
public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); final BlockingQueue<String> queue = new LinkedBlockingQueue<>(); executor.execute(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { System.out.println("first interrupted!!!"); } System.out.println(Thread.currentThread().isInterrupted()); try { queue.take(); } catch (InterruptedException e) { System.out.println("second interrupted!!!"); } } }); executor.shutdownNow(); }
還有更讓人受不了的,如果我們在任務最開始隨便寫點什么,就會按照我們期待的執行了(心中一萬只草泥馬呀)
public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(new Runnable() { @Override public void run() { System.out.println("xxxx"); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { System.out.println("first interrupted!!!"); } System.out.println(Thread.currentThread().isInterrupted()); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { System.out.println("second interrupted!!!"); } } }); executor.shutdownNow(); }
以后有機會再研究吧,可能還是知識不夠吧!!!!