Java Thread.sleep泄漏线程?

时间:2012-01-18 17:41:05

标签: java memory-leaks sleep thread-sleep

所以我继承了一些等待来自网络源的通信的代码。

当它正在等待来自网络套接字的更多数据时,会调用Thread.sleep(10)。这似乎导致了线程泄漏,正如jconsole和我的线程转储所报告的那样(Thread-68,Thread-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

我有一些担心,用这个频率调用睡眠可能会导致问题,我已经尝试将睡眠时间从10增加到250只是为了缓解这种情况。这确实有所改善,但随着时间的推移,我仍然遇到同样的问题 - 我一直在泄漏线程,直到我没有堆空间。

有没有人对此行为有任何见解?我不认为像Thread.sleep()那样基本的东西会导致像这样的问题。

4 个答案:

答案 0 :(得分:9)

Thread.sleep()肯定不是问题。它不会创建任何线程等。

我只能猜测isRunning从未设置过(或由于同步不佳而导致更改不可见),并且在旧的线程仍在运行时会创建新线程。

BTW而不是经常调用available并且休眠线程可以简单地阻止input.read()。代码会更简单,响应更快。

答案 1 :(得分:6)

问题不在于Thread.sleep(),而在于线程的逻辑。

从您发布的代码中,线程将在isRunning = false时终止。现在,将isRunning设置为false的唯一方法是input.available()返回正值,然后input.read()返回负值。

在那种情况下似乎没有任何世界状态。

因此,使用此run()方法的所有主题都将在该过程存活期间存活,并将大部分时间花在Thread.sleep()上。

P.S。这是基于您发布的代码。如果 方式将isRunning设置为您当前未显示的false,请更新您的问题。

答案 2 :(得分:2)

Thread.sleep()不会“分叉”任何内容,在搜索线程泄漏时无法考虑...

您应该搜索生成这些线程的内容。哪一段代码负责在您的应用程序中创建新线程?这是你必须首先回答的问题

答案 3 :(得分:1)

要犯的一个常见错误是忘记创建isRunning布尔volatile如果没有此关键字,您可以在一个线程中更改它,并且无法保证另一个线程将看到该更改。所以你可能将isRunning设置为false,但线程继续运行。

为了解决这个问题,我会以简洁的方式简化代码,以便它可以在这样的变量上旋转。     private volatile boolean closed = false;     private final InputStream input;

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
  }
}

你做得越简单,就越有可能工作。 ;)