2012-01-18 130 views
3

因此,我繼承了一些代碼,它們正在等待來自網絡源的通信。Java Thread.sleep泄漏線程?

當它正在等待來自網絡套接字的更多數據時,Thread.sleep(10)被調用。這似乎是導致線程泄漏,如JConsole的報道,在這裏我的線程轉儲(也有數百個條目的主題-68,螺紋385,等...但我縮短了簡潔):

Wed Jan 18 09:14:40 PST 2012 
2012-01-18 09:14:50 
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b11 mixed mode): 

"Thread-69" daemon prio=10 tid=0x00007f01a047c800 nid=0x3725 waiting on condition [0x00007f019eaf4000] 
    java.lang.Thread.State: TIMED_WAITING (sleeping) 
     at java.lang.Thread.sleep(Native Method) 
     at com.unitt.framework.websocket.simple.NetworkSocket.run(NetworkSocket.java:304) 
     at java.lang.Thread.run(Thread.java:662) 

"Thread-68" daemon prio=10 tid=0x00007f01a0500000 nid=0x371c waiting on condition [0x00007f019ecf6000] 
    java.lang.Thread.State: TIMED_WAITING (sleeping) 
     at java.lang.Thread.sleep(Native Method) 
     at com.unitt.framework.websocket.simple.NetworkSocket.run(NetworkSocket.java:304) 
     at java.lang.Thread.run(Thread.java:662) 

有問題的代碼:

public class NetworkSocket implements NetworkSocketFacade, Runnable 
{ 

... removed many irrelevant methods 

public void run() 
{ 
    byte[] readBuffer = new byte[512 * 1024]; 
    while (isRunning) 
    { 
     //ioLogger.debug("in while(isRunning) loop"); 
     try 
     { 
      int length = input.available(); 
      if (length > 0) 
      { 
       int read = input.read(readBuffer, 0, readBuffer.length); 

       if (read < 0) 
       { 
        isRunning = false; 
        //@todo: do we disconnect? 
        ioLogger.debug("setting isRunning FALSE after read < 0"); 
       } 
       else 
       { 
        //read data and process 
       } 
      } 
      else 
      { 
       //ioLogger.debug("nothing to read, sleeping"); 
       try 
       { 
        Thread.sleep(10); 
       } 
       catch (InterruptedException e) 
       { 
        //do nothing, keep going 
       } 
      } 
     } 
    // some catch blocks and logging after this 

我有一些擔心調用sleep這個頻率可能會出現問題,我已經試過增加10至250的睡眠時間只是爲了緩和局勢。這確實有助於改善問題,但隨着時間的推移,我仍然會遇到同樣的問題 - 我穩定地泄漏線程,直到我離開堆空間。

有沒有人有任何見解這種行爲?我不認爲像Thread.sleep()那樣基本的東西會導致這樣的問題。

+0

這種「線程泄漏」的假設機制是什麼? 'Thread.sleep()'永不返回? – NPE 2012-01-18 17:45:54

+0

當我看着我的jconsole線數時,我不確定還有什麼叫它,它以30度的角度攀爬了18個小時。新線程不斷創建,所有舊線程都停留在上面列出的「等待狀態」位置。 – AWT 2012-01-18 17:54:52

回答

5

問題不在於Thread.sleep(),它與線程的邏輯有關。

從您發佈的代碼中,線程將在isRunning = false時終止。現在,將isRunning設置爲false的唯一方法是input.available()返回正值,然後input.read()返回負值。

當情況確實如此時,世界上似乎沒有任何狀態。

因此,使用此run()方法的所有線程都會一直存在,只要進程處於活動狀態,大部分時間都花在Thread.sleep()之上。

P.S.這是基於您發佈的代碼。如果isRunning的方式設置爲false,您目前沒有顯示,請更新您的問題。

+0

嗨@aix,感謝您的幫助。仔細查看代碼,沒有其他方法將isRunning設置爲false,此代碼之外的唯一對isRunning的引用是聲明。檢查這是出於某種有缺陷的設計還是僅僅是一個缺陷。 – AWT 2012-01-18 19:23:09

+1

原來這就是問題所在。在我對Java的經驗不足時,我正在解釋我的堆棧跟蹤結果,認爲Thread.sleep()掛起,實際上我有很多無限期睡眠的線程。我添加了一些錯誤檢查,讓線程有一段時間在網絡端口上等待數據,並且問題消失了。感謝大家的迴應。 – AWT 2012-01-19 18:14:22

9

Thread.sleep()確實沒有問題。它不會創建任何線程或類似的東西。

我只能猜測isRunning從未設置(或者由於同步不良而導致更改不可見),並且創建新線程,而舊線程仍在運行。

順便說一句,而不是經常呼籲available和睡覺的線程可以簡單地阻止input.read()。代碼將會更加簡單和快速響應。

+0

我現在正在查看代碼。我猜是什麼讓我感到所有的線程都被困在Thread.sleep()中。 – AWT 2012-01-18 17:57:56

+0

+1。我的猜測是,可用總是返回0由於某種原因(例如連接重置),並且線程無休止地循環而不是讀取和獲得IOException。可用是不可靠的,它不應該被使用。 – 2012-01-18 17:58:31

2

Thread.sleep()不「叉」任何東西,不能被考慮,而搜索關於螺紋泄漏...

你應該尋找什麼生產這些線程。哪一段代碼負責在應用程序中創建新線程?這是你必須先回答的問題

+0

好點。我想我找到了一些有趣的東西,讓我把它整理出來,然後我會在這裏發佈。 – AWT 2012-01-18 18:04:07

1

一個常見的錯誤是忘記做一個isRunning boolean volatile沒有這個關鍵字,你可以在一個線程中改變它,並且不保證另一個線程會看到這個改變。所以你可以設置isRunning爲false,但線程繼續運行。

爲了解決這個問題,我會簡化代碼,所以它會在這個變量上旋轉。 private volatile boolean closed = false; private final InputStream輸入;

public void close() throws IOException { 
    closed = true; 
    input.close(); 
} 

public void run() { 
    byte[] readBuffer = new byte[512 * 1024]; 
    try { 
    // you wouldn't keep looping after an exception. 
    int len; 
    while ((len = input.read(readBuffer)) > 0) { 
      //read data and process 
    } 
    } catch (IOException ioe) { 
    if (!closed) 
     // log unexpected exception 
    } 
} 

你做得越簡單,工作的可能性就越大。 ;)