1

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

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

4 回答 4

1

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

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

于 2009-12-26T17:38:11.603 回答
1

看起来你的代码做了你想做的事。如果您查看您的命名,您可以使您的代码更容易理解,例如布尔“关闭”可以命名为“关闭”或“关闭”或将其反转为“运行”,这将导致更可读的代码恕我直言。

while 循环run()和它后面的行可以写成:

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

        out.output(pipe.get());
    }
于 2009-12-26T10:20:10.327 回答
0

不知道为什么关闭时要尝试清洁管道,为什么不丢弃它并让 GC 清理它?据我所知,您所需要的只是关闭和第一个循环。

于 2009-12-26T10:07:22.777 回答
0

如果您想在流程停止之前处理管道中的所有元素,我认为我实际上不会使用关闭挂钩 - 我会在主代码中明确关闭管道,然后等待它完成让主线程完成。我建议您要么将close()方法更改为阻塞,直到管道完成,要么添加一个单独的方法(例如waitForPipelineToEmpty())。

通过这种方式,您可以使其更加可控 - 特别是,这意味着您不会在系统的其他部分在关闭挂钩中自行清理时尝试处理事物。

终止生产者/消费者队列的另一种方法是设置一个哨兵值,这意味着“现在停止”。然后,您只需将其输入到管道的末尾(并避免添加更多“真实”值)-您的处理器在看到该项目时就会停止。

于 2009-12-26T10:23:23.617 回答