Поток Java.сон протекает нитями?


Итак, я унаследовал немного кода, который ожидает связи из сетевого источника.

Пока он ждет дополнительных данных из сетевого сокета, вызывается Thread.sleep(10). Это, по-видимому, вызывает утечку потока, о чем сообщают jconsole и My thread dump здесь (есть сотни записей для 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 3

4 ответа:

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

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

Кажется, что нет такого состояния мира, когда это было бы так.

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

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

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

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

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

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

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

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

Чтобы решить эту проблему, я бы упростил код даматически, чтобы он вращался вокруг переменной, подобной этой. частная летучих логическое закрыт = ложь; частная окончательной входного потока;

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
  }
}

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