在终止前清洁缓冲区

时间:2009-12-26 09:59:03

标签: java concurrency termination

我正在编写类似于生产者 - 消费者问题的程序。这是我的主要代码:

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()方法由关闭钩子调用,我确保在处理器关闭时缓冲区没有被填充, 这是正确的方法吗?谢谢。

4 个答案:

答案 0 :(得分:1)

您的代码看起来像您希望它做的那样。如果查看命名,可以使代码更容易理解,例如布尔“close”可以命名为“closing”或“shuttingDown”,或者将其反转为“running”,这将导致更易读的代码。

run()中的while循环及其后面的行可以写成:

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

        out.output(pipe.get());
    }

答案 1 :(得分:1)

我担心out.close()不一定会被调用。如果Pipe.get()阻塞像ArrayBlockingQueue.take()并且它在检测到闭包时没有返回sentinel值,那么在Pipe为空之后在PipeProcessor上调用close()将没有效果,因为while(!close)条件不会再次评估。

但也许(1)Pipe总是先关闭,(2)Pipe.get()确实检测到闭包,(3)它返回一些像null那样的输出可以处理的Sentinel值。如果是这种情况,那么您的代码看起来不错。

答案 2 :(得分:0)

不确定为什么要在关闭时尝试清洁管道,为什么不丢弃它并让GC清理它?就我所见,你所需要的就是闭合和第一个循环。

答案 3 :(得分:0)

如果你想在进程停止之前处理管道中的所有元素,我认为我实际上并没有使用关闭钩子 - 我在主代码中明确地关闭了管道,并等待它让主线完成之前完成。我建议您更改close()方法,直到管道完成为止,或者添加单独的方法(例如waitForPipelineToEmpty())。

通过这种方式,你可以使它更具可控性 - 特别是,它意味着当系统的其他部分在关机钩子中清理它们时,你不会试图处理事物。

终止生产者/消费者队列的另一种方法是使用Sentinel值,这意味着“立即停止”。然后,您只需将其输入管道的末尾(并避免添加任何“真实”值) - 并且您的处理器在看到该项目时就会停止。