2012-01-18 129 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 
    } 
} 

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