我正在编写类似于生产者 - 消费者问题的程序。这是我的主要代码:
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()方法由关闭钩子调用,我确保在处理器关闭时缓冲区没有被填充, 这是正确的方法吗?谢谢。
答案 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值,这意味着“立即停止”。然后,您只需将其输入管道的末尾(并避免添加任何“真实”值) - 并且您的处理器在看到该项目时就会停止。