Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Thread.sleep leaking threads?

So I inherited a bit of code that's waiting for communication from a network source.

While it's waiting for more data from the network socket, Thread.sleep(10) is called. This appears to be causing a thread leak, as reported by jconsole and my thread dump here (there are hundreds of entries for Thread-68, Thread-385, etc... but I shortened for brevity):

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)

The code in question:

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

I have some worries that calling sleep with this frequency can cause problems and I've tried increasing the sleep time from 10 to 250 just to allay the situation. That does improve matters somewhat, but over time I still end up with the same problem - I steadily leak threads until I am out of heap space.

Does anyone have any insights into this behavior? I wouldn't think that something as basic as Thread.sleep() would cause problems like this.

like image 445
AWT Avatar asked Dec 02 '22 00:12

AWT


2 Answers

Thread.sleep() is not a problem for sure. It does not create any threads or such.

I can only guess that isRunning is never set (or the change is not visible due to poor synchronization) and new threads are created while old ones are still running.

BTW instead of constantly calling available and sleeping the thread can simply block on input.read(). Code would be much simpler and more responsive.

like image 70
Tomasz Nurkiewicz Avatar answered Dec 15 '22 08:12

Tomasz Nurkiewicz


The problem isn't with Thread.sleep(), it's with the thread's logic.

From the code that you've posted, the thread will terminate when isRunning = false. Now, the only way for isRunning to be set to false is when input.available() returns a positive value, followed by input.read() returning a negative value.

There doesn't appear to be any state of the world when that would be the case.

As a result, all of the threads using this run() method will live for as long as the process lives, spending most of their time in Thread.sleep().

P.S. This is based on the code that you've posted. If there are ways for isRunning to be set to false that you're not currently showing, please update your question.

like image 25
NPE Avatar answered Dec 15 '22 09:12

NPE