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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With