Очистка буфера перед завершением - PullRequest
1 голос
/ 26 декабря 2009

Я пишу программу, аналогичную проблеме производителя-потребителя. Вот мой основной код:

public class PipeProcessor {

private volatile boolean close = false;

Pipe pipe;
Output out;

public PipeProcessor(Pipe pipe)
{
    this.pipe = pipe;
}

public void run()
{
    while(!close)
    {
        out.output(pipe.get());
    }

    while(pipe.size() > 0)
        out.output(pipe.get());

    out.close();

}

public void close()
{
    close = true;
}
}

Pipe - это оболочка для ArrayBlockingQueue и действует как буфер. Выход - это класс, который берет элемент в буфере и выводит его.

Я хочу убедиться, что PipeProcessor завершается корректно, то есть, когда сигнализируется о закрытии, он очищает буфер. Так как метод close () вызывается ловушкой shutdown, я проверяю, что буфер не заполняется во время закрытия процессора, Это правильный способ сделать это? Спасибо.

Ответы [ 4 ]

1 голос
/ 26 декабря 2009

Я обеспокоен тем, что out.close () не обязательно будет вызван. Если Pipe.get () блокирует как ArrayBlockingQueue.take () , и он не возвращает значение часового, когда обнаруживает закрытие, то вызов close () для PipeProcessor после того, как Pipe пуст, не будет иметь никакого эффекта, потому что условие while (! close) больше не будет оцениваться.

Но, возможно, (1) труба всегда будет закрыта первой, (2) Pipe.get () обнаружит закрытие и (3) вернет некоторое значение часового типа, например, null, которое может обработать Output. Если это так, то ваш код выглядит хорошо.

1 голос
/ 26 декабря 2009

Похоже, ваш код делает то, что вы хотите. Вы могли бы сделать ваш код более легким для понимания, если взгляните на свое именование, например, логическое «close» можно назвать «close» или «shuttingDown» или инвертировать его на «running», что приведет к более читаемому коду imho.

Цикл while в run() и следующие за ним строки могут быть записаны как:

    while (running || pipe.size() > 0) {

        out.output(pipe.get());
    }
0 голосов
/ 26 декабря 2009

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

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

Один из альтернативных способов завершения очереди производителя / потребителя состоит в том, чтобы иметь значение Sentinel, которое означает «остановить сейчас». Затем вы просто подаете это в конец конвейера (и не добавляете больше «реальных» значений) - и ваш процессор просто останавливается, когда видит этот элемент.

0 голосов
/ 26 декабря 2009

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

...