Подтвердить что ты не робот

Java: Является ли `while (true) {...}` loop in thread bad? Какая альтернатива?

Является ли while (true) { ... } петлей в потоках плохой? Какая альтернатива?

Обновление; что я пытаюсь...

У меня есть ~ 10000 потоков, каждый из которых отправляет сообщения из своих частных очередей. У меня есть один поток, который создает сообщения один за другим и помещает их в правильную очередь потребителей. Каждая потребительская цепочка бесконечно циклически проверяет наличие сообщения в очереди и обрабатывает его.

Внутри Consumer.java:

@Override
public void run() {
    while (true) {
        Message msg = messageQueue.poll();
        if (msg != null) {
            ... // do something with the message
        }
    }
}

Продюсер быстро вводит сообщения в очереди сообщений потребителей (несколько миллионов сообщений в секунду). Потребители должны обрабатывать эти сообщения как можно быстрее!

Примечание: while (true) { ... } завершается сообщением KILL, отправленным Проджетором в качестве последнего сообщения. Тем не менее, мой вопрос заключается в правильном способе выполнения этой передачи сообщений...

Посмотрите новый вопрос относительно этого дизайна.

4b9b3361

Ответ 1

Вместо того, чтобы зацикливаться навсегда и ломаться или возвращаться, вы можете проверить прерванный статус.

while (!Thread.currentThread().isInterrupted()) {
    try {
        doWork();
        wait(1000);
    } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
}

Если ваши потоки - это задачи, управляемые ExecutorService, вы можете просто закончить их, просто позвонив shutdownNow().

Ответ 2

while (!stop_running) { ... }

... возможно? Для управления потоком часто используется некоторый флаг выхода.

Ответ 3

Не по своей сути, нет. Вы всегда можете заручиться с помощью break или return. Просто убедитесь, что вы на самом деле (в какой-то момент)

Проблема в том, что происходит, когда ваш поток не имеет ничего общего? Если вы просто обходите вокруг и проверяете состояние, ваш поток будет поглощать весь процессор, ничего не делая. Поэтому не забудьте использовать wait, чтобы заблокировать поток, или sleep, если у вас нет ничего в wait.

Ответ 4

Зависит от определения "плохо". Это означает, что человек, пытающийся прочитать код, должен искать в другом месте по той причине, что цикл завершен. Это может сделать его менее читаемым.

Этот менталитет достиг предельных результатов в ключевом слове COMEFROM. http://en.wikipedia.org/wiki/COMEFROM

10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM

Ответ 5

Лучше иметь условие завершения в строке while (...), но иногда условие завершения - это то, что вы можете только проверить где-то глубоко внутри цикла. Тогда то, что break для (или исключений). На самом деле, может быть, ваш поток должен работать вечно до тех пор, пока ваша программа не завершится (с System.exit); то while (true) определенно прав.

Но, может быть, вы спрашиваете, что должно идти внутри цикла. Вам нужно включить некоторую операцию блокировки, т.е. Вызвать какой-либо вызов функции, где ваш поток будет ждать кого-то другого (другой поток, другая программа, ОС), чтобы что-то сделать. Обычно это Condition.wait, если вы программируете с помощью блокировок или чтения из очереди сообщений или чтения из файла или сетевого сокета или какой-либо другой операции блокировки ввода-вывода.

Обратите внимание, что sleep обычно недостаточно. Вы не можете знать, когда другие участники собираются что-то сделать, поэтому нет возможности избежать слишком частого пробуждения (таким образом, сжигая время процессора без необходимости) или слишком редко (таким образом, своевременно не реагируя на события). Всегда создавайте свою систему так, чтобы, когда поток завершил свое задание, он уведомляет того, кто ждет этого задания (часто с Condition.signal или путем присоединения).

Ответ 7

Обычно я использую атрибут класса boolean, называемый "done", тогда методы запуска потоков выглядят как

done = false;
while( !done ) {
    // ... process stuff
}

Затем вы можете установить done = true, чтобы убить цикл. Это можно сделать изнутри цикла, или у вас может быть другой метод, который устанавливает его, чтобы другие потоки могли вытащить вилку.

Ответ 8

while (true) не плохо, если есть способ выйти из цикла, иначе вызов будет выполняться неограниченно.

Для 10000 потоков, выполняющих вызов while(true), является плохая практика... почему у вас нет sleep() в потоке, чтобы разрешить запуск других потоков или стратегию выхода, если поток завершен?

Ответ 9

Похоже, вы заняты, ожидая стандартного BlockingQueue. Используйте take вместо poll.

Кроме этого, for (;;) лучше, чем while (true), IMO.

Ответ 10

Если бы я делал то, о чем вы говорите, я бы попробовал это:

private Object lock = new Object();    

public void run(){
    while(true){
        synchronized(lock){
            Message msg = messageQueue.poll();
            if (msg != null) {
                ... // do something with the message
            }else{
                try{
                    lock.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                    continue;
                }
            }
        }
    }
}

Это позволяет вам убедиться, что вы не получаете каких-либо параллельных изменений в своем сообщении, а также когда нет сообщения, вы не будете использовать время процессора в цикле while (true). Теперь вам просто нужно убедиться, что когда вы добавите что-то в свой messageQueue, вы можете вызвать lock.notifyAll(), чтобы поток знал, что нужно снова запустить.