Поток 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 ответа:
Проблема не в
Thread.sleep(), а в логике потока.Из кода, который вы опубликовали, поток завершится, когда
Кажется, что нет такого состояния мира, когда это было бы так.isRunning = false. Теперь единственный способ дляisRunningустановить значениеfalse- это когдаinput.available()возвращает положительное значение, а затемinput.read()возвращает отрицательное значение.В результате все потоки, использующие этот метод
P.S. Это основано на коде, который вы опубликовали. Если есть способы дляrun(), будут жить так долго, как живет процесс., большую часть времени они проводят вThread.sleep().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 } }Чем проще вы сделайте это, тем более вероятно, что это сработает. ;)