【问题标题】:Java Thread.sleep leaking threads?Java Thread.sleep 泄漏线程?
【发布时间】:2012-01-18 17:41:05
【问题描述】:

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

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

我有些担心以这种频率调用 sleep 会导致问题,我尝试将 sleep 时间从 10 增加到 250 以缓解这种情况。这确实在一定程度上改善了问题,但随着时间的推移,我仍然会遇到同样的问题——我会不断泄漏线程,直到堆空间用完。

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

【问题讨论】:

  • 这种“线程泄漏”的假定机制是什么? Thread.sleep() 永远不会回来?
  • 当我查看我的 jconsole 线程数时,我不确定还能叫它什么,它以 30 度角攀爬 18 小时。新线程不断被创建,所有旧线程都停留在我上面列出的“等待条件”位置。

标签: java memory-leaks sleep thread-sleep


【解决方案1】:

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

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

顺便说一句,与其不断调用available 并让线程休眠,不如简单地阻塞input.read()。代码会更简单,响应更快。

【讨论】:

  • 我现在正在回顾代码。我想让我感到震惊的是所有线程都卡在 Thread.sleep() 上。
  • +1。我的猜测是,由于某种原因(例如连接重置),available 总是返回 0,并且线程会无限循环,而不是读取并获取 IOException。 available 只是不可靠的,不应该使用。
【解决方案2】:

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

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

世界上似乎没有任何状态会出现这种情况。

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

附:这是基于您发布的代码。如果有种方法可以将isRunning 设置为false,而您目前没有显示,请更新您的问题。

【讨论】:

  • 嗨@aix,感谢您的帮助。查看代码,没有其他方法可以将 isRunning 设置为 false,此代码之外对 isRunning 的唯一引用是声明。检查这是由一些有缺陷的设计还是只是一个缺陷。
  • 原来这正是问题所在。在我对 Java 缺乏经验的情况下,我将堆栈跟踪的结果解释为认为 Thread.sleep() 挂起,而实际上我有许多线程无限期地处于休眠状态。我添加了一些错误检查,在等待网络端口上的数据时给了线程一段时间,问题就消失了。感谢大家的回复。
【解决方案3】:

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

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

【讨论】:

  • 好点。我想我发现了一些有趣的东西,让我整理一下,然后我会在这里发布。
【解决方案4】:

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

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

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

【讨论】:

    猜你喜欢
    • 2016-12-09
    • 2012-02-17
    • 2020-04-06
    • 1970-01-01
    • 2022-10-05
    • 2015-05-20
    • 2014-10-29
    • 2011-09-13
    • 2013-12-18
    相关资源
    最近更新 更多