所以我继承了一些等待来自网络源的通信的代码。
当它正在等待来自网络套接字的更多数据时,会调用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()
那样基本的东西会导致像这样的问题。
答案 0 :(得分:9)
Thread.sleep()
肯定不是问题。它不会创建任何线程等。
我只能猜测isRunning
从未设置过(或由于同步不佳而导致更改不可见),并且在旧的线程仍在运行时会创建新线程。
BTW而不是经常调用available
并且休眠线程可以简单地阻止input.read()
。代码会更简单,响应更快。
答案 1 :(得分:6)
问题不在于Thread.sleep()
,而在于线程的逻辑。
从您发布的代码中,线程将在isRunning = false
时终止。现在,将isRunning
设置为false
的唯一方法是input.available()
返回正值,然后input.read()
返回负值。
在那种情况下似乎没有任何世界状态。
因此,使用此run()
方法的所有主题都将在该过程存活期间存活,并将大部分时间花在Thread.sleep()
上。
P.S。这是基于您发布的代码。如果 方式将isRunning
设置为您当前未显示的false
,请更新您的问题。
答案 2 :(得分:2)
Thread.sleep()
不会“分叉”任何内容,在搜索线程泄漏时无法考虑...
您应该搜索生成这些线程的内容。哪一段代码负责在您的应用程序中创建新线程?这是你必须首先回答的问题
答案 3 :(得分:1)
要犯的一个常见错误是忘记创建isRunning
布尔volatile
如果没有此关键字,您可以在一个线程中更改它,并且无法保证另一个线程将看到该更改。所以你可能将isRunning
设置为false,但线程继续运行。
为了解决这个问题,我会以简洁的方式简化代码,以便它可以在这样的变量上旋转。 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
}
}
你做得越简单,就越有可能工作。 ;)