2012-08-16 76 views
1

我正在研究通過網絡讀取和處理數據的應用程序。在測試程序的連接/斷開邏輯時,我注意到我的消費者線程在達到關閉狀態時未關閉。以下是消費者類的一個精簡版。調用interrupt()時不拋出InterruptedException的線程

import java.io.InputStream; 

public class Consumer implements Runnable 
{ 
    private final InputStream input; 
    public Consumer(InputStream input) 
    { 
     this.input = input; 
    } 
    @Override 
    public void run() 
    {  
     byte readBuffer[]; 
     readBuffer = new byte[1]; 
     int goodData; 

     try 
     { 
     while(input.available() > 0) 
     { 
      goodData = input.read(readBuffer); 
      while (goodData > 0) 
      { 
       System.out.println(readBuffer[0]); 
       if (readBuffer[0] == 27) 
       { 
        System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName()); 
        //this is the last packet, so interupt thread to close 
       Thread.currentThread().interrupt(); 
       //return; 
       //Thread.currentThread().stop(new InterruptedException("Attempting to close")); 
       } 
       goodData = input.read(readBuffer); 
      } 
     } 
     } 
     catch(Exception e) 
     { 
     System.out.println("closing "+Thread.currentThread().getName() +" because of an exception "+e.getClass()); 
     return; 
     } 
     System.out.println("closing "+Thread.currentThread().getName()); 
    } 
} 

我創建了一個虛擬主類來演示這個問題。

public class ExampleOfInterruptNotWorking 
{ 
    public static void main(String[] args) 
    { 
     byte[] bytesToWrite = new byte[]{0, 1, 2,3,4,5,6,65,23,65,21,54,13,54,1,76}; 
     Consumer C; 
     Thread ConsumerThread; 
     PipedInputStream PIS = null; 
     PipedOutputStream POS = null; 
     try 
     { 
     PIS = new PipedInputStream(); 
     POS = new PipedOutputStream(PIS); 
     C = new Consumer(PIS); 
     ConsumerThread = new Thread(C); 

     ConsumerThread.start(); 

     POS.write(bytesToWrite); 
     POS.write(bytesToWrite); 
     bytesToWrite[1] = 27; 
     POS.write(bytesToWrite); 

     ConsumerThread.join(); 

     } 
     catch(Exception e) 
     { 
     System.err.println("Unexpected exception in main"); 
     e.printStackTrace(System.err); 
     } 
     finally 
     { 
     try 
     { 
      PIS.close(); 
      POS.close(); 
     } 
     catch(Exception ex) 
     { 
     //shouldn't happen in example 
     } 
     System.out.println("exiting main"); 
     } 
    } 
} 

當您運行書面此代碼,消費者檢測到中斷,但直到管道是空不停止執行(不是我想要的)。只是嘗試,我改變了一個Thread.stop()調用,它做了我想要的,但我不想在生產代碼中留下它。我意識到我可以使用一個簡單的return語句,但這不是線程可以退出的唯一一點,我想要一些通用的退出代碼來清理資源。所以,我的問題是,消費者線程爲什麼不被打斷?對我來說能夠擁有共同的退出代碼有一個好方法嗎?

謝謝!

+0

,因爲它沒有等待這不是打斷你並沒有把它的消息。好的方法是在完成寫作時關閉流。 – 2012-08-16 12:05:37

+0

返回聲明看起來像你最好的選擇。你能否試圖證明你說你不能創建「清理資源的一些常見退出代碼」的問題?通常,你在finally塊中這樣做。 – 2012-08-16 12:06:09

+0

@RomanC我真的不喜歡在正在讀取它們的東西下面關閉流。在這種特殊情況下,我收到了關閉連接請求的返回消息。在設計應用程序的過程中,我不能保證收到的信息是最後發送的信息。正如它在下面發佈的「異常是例外情況」和關閉流會導致IOException - 當我已經知道流正在關閉。 – adeady 2012-08-16 12:20:33

回答

9

當一個線程正在休眠,等待一個連接等(基本上是任何可中斷的阻塞調用)和interrupt()被調用時,會引發InterruptedExceptions。

如果你的線程正在運行,那麼線程中斷標誌將被設置,但不會拋出異常,你應該檢查標誌myThread.isInterrupted()

你可以在這裏找到更多的信息: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html

+0

感謝您的參考。我假設interrupt()調用實際上中斷了線程。如果它只是設置狀態位,那就更有意義了。 – adeady 2012-08-16 12:24:34

+0

+1,以獲得良好的文章鏈接。很明顯,應該在run()方法中添加while(!Thread.currentThread()。isInterrupted())...(或類似的檢查)來解決問題 – Brad 2012-08-16 13:45:03

2

您希望拋出哪種方法InterruptedExceptionThread.interrupt()不是扔它,既不是你的任何方法。那麼你預計這個檢查異常應該從哪裏來?

您的代碼無效,因爲interrupt()幾乎不會在線程上設置interrupted標誌。您必須使用Thread.isInterrupted()明確檢查該標誌。 InterruptedException只在當前線程處於睡眠或阻塞狀態時纔會拋出。所以如果你打斷不同線程和那個線程正在睡覺,sleep()將拋出InterruptedException

現在來詳細解決你的問題。 例外情況適用於例外情況。你的線程完成處理的事實並非特例,這是你一定期待的。出於同樣的原因,讀取超過最後的文件不會拋出異常 - 文件結尾是您應該期望的 - 所有文件都已結束。此外,您不應該使用異常來控制程序流。

在你的情況下,使用return語句(當run()返回,線程死亡)或以其他方式破壞你的循環。你發佈了太多的代碼來分析。

0

你可以簡單地使用break標記

OUTER: 
    while(input.available() > 0) 
    { 
     goodData = input.read(readBuffer); 
     while (goodData > 0) 
     { 
      System.out.println(readBuffer[0]); 
      if (readBuffer[0] == 27) 
      { 
       System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName()); 
       //this is the last packet, so interupt thread to close 
      //Thread.currentThread().interrupt(); 
      break OUTER; 
      //return; 
      //Thread.currentThread().stop(new InterruptedException("Attempting to close")); 
      } 
      goodData = input.read(readBuffer); 
     } 
    } 
相關問題