Java Thread.sleep подтекает темы? - PullRequest
       9

Java Thread.sleep подтекает темы?

4 голосов
/ 18 января 2012

Итак, я унаследовал немного кода, ожидающего соединения от сетевого источника.

Пока он ожидает получения дополнительных данных от сетевого сокета, вызывается 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(), могут вызвать такие проблемы.

Ответы [ 4 ]

9 голосов
/ 18 января 2012

Thread.sleep() точно не проблема.Он не создает никаких потоков или чего-либо подобного.

Я могу только догадываться, что isRunning никогда не устанавливается (или изменение не видно из-за плохой синхронизации) и новые потоки создаются, пока старые еще работают.

Кстати, вместо того, чтобы постоянно звонить available и спать поток может просто заблокировать input.read().Код был бы намного проще и отзывчивее.

6 голосов
/ 18 января 2012

Проблема не в Thread.sleep(), а в логике потока.

Из кода, который вы разместили, тема прекратит работу, когда isRunning = false. Теперь единственный способ установить isRunning на false - это когда input.available() возвращает положительное значение, а затем input.read() возвращает отрицательное значение.

Похоже, что в мире не было бы такого состояния.

В результате все потоки, использующие этот метод run(), будут жить так же долго, как и процесс, проводя большую часть своего времени в Thread.sleep().

P.S. Это основано на коде, который вы опубликовали. Если есть способ установить для isRunning значение false, которое в данный момент не отображается, обновите свой вопрос.

2 голосов
/ 18 января 2012

Thread.sleep() ничего не «разветвляет» и не может быть учтено при поиске утечки потоков ...

Вы должны искать, что производит этих потоков.Какая часть кода отвечает за создание новых потоков в вашем приложении?На этот вопрос вы сначала должны ответить

1 голос
/ 19 января 2012

Распространенная ошибка - забыть создать isRunning логическое volatile Без этого ключевого слова вы можете изменить его в одном потоке, и нет гарантии, что другой поток увидит это изменение. Таким образом, вы можете установить для isRunning значение false, но поток продолжает работать.

Чтобы решить эту проблему, я бы существенно упростил код, чтобы он вращался вокруг такой переменной, как эта. private volatile логическое значение closed = 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
  }
}

Чем проще вы это сделаете, тем больше вероятность, что это сработает. ;)

...