4

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

当它等待来自网络套接字的更多数据时,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

4 回答 4

9

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

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

available顺便说一句,线程可以简单地阻塞而不是不断调用和休眠input.read()。代码会更简单,响应更快。

于 2012-01-18T17:45:12.797 回答
6

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

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

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

因此,所有使用此run()方法的线程将与进程一样长,大部分时间都在Thread.sleep().

PS 这是基于您发布的代码。如果有一些方法isRunning可以设置为false您当前未显示,请更新您的问题。

于 2012-01-18T18:00:02.960 回答
2

Thread.sleep()在搜索线程泄漏时不会“分叉”任何东西并且不能被考虑在内......

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

于 2012-01-18T17:46:07.530 回答
1

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

为了解决这个问题,我会大幅简化代码,这样它就可以在这样的变量上旋转。私人易失性布尔关闭=假;私有最终 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
  }
}

你做得越简单,它就越有可能奏效。;)

于 2012-01-18T20:25:09.570 回答