问题
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.
回答1:
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.
回答2:
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.
回答3:
Thread.sleep()
doesn't "fork" anything and cannot be taken into account while searching about Thread leakage...
You should search for what is producing these threads. Which is the piece of code responsible of creating new threads in your application ? That's the question you'll have to answer first
回答4:
A common mistake to make is to forget to make an isRunning
boolean volatile
Without this keyword you can change it in one thread and there is no guarantee another thread will see that change. So you could be setting isRunning
to false, but the thread continues to run.
To fix the problem I would simplify the code damatically so it does spin around on a variable like this. 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
}
}
The simpler you make it, the more likely it is to work. ;)
来源:https://stackoverflow.com/questions/8914735/java-thread-sleep-leaking-threads