具有消费者完成通知的Java Producer Consumer Pattern

时间:2013-06-18 11:46:21

标签: java multithreading producer-consumer

我想实现一个生产者/消费者场景,其中我有多个生产者和一个消费者。生产者不断将项目添加到队列中,并且消费者将项目排队。当消费者处理了足够的物品时,生产者和消费者都应该停止执行。消费者在处理足够的物品时可以轻松地自行终止。但生产者也应该知道什么时候退出。典型的生产者毒丸在这里不起作用。

一种方法是在消费者和生产者之间建立一个共享的布尔变量。 Consumer将布尔变量设置为true,生成器定期检查变量,如果设置为true则退出。

关于我如何做到这一点的任何更好的想法?

4 个答案:

答案 0 :(得分:3)

我想你可以有一个共享的计数器,并且有一个最大值。如果增量大于最大值,则线程无法添加到队列中。

private final AtomicInteger count = new AtomicInteger(0);
private final int MAX = ...;/
private final BlockingQueue<T> queue = ...;
public boolean add(T t){
    if(count.incrementAndGet() > MAX) 
           return false;

    return queue.offer(t);
}

答案 1 :(得分:0)

不确定这种方法是否有用。

  • 在消息中包含对生产者的引用。
  • Producer提供了一个回调方法来告诉他们停止生成。
  • 消费者根据唯一的引用集保留生产者注册表 传递给它。
  • 当消费者已经受够了,它会遍历生产者的注册表,并通过调用回调方法告诉他们停止。

仅在生产者和消费者位于同一JVM中时才有效 不会阻止任何新的制作人启动

而且我不确定它是否会维持生产者和消费者的分离

或者,由于Queue是这两个对象之间的共享资源,您是否可以在队列中引入“isOpen”状态,该状态在生产者写入之前进行检查,并由消费者在完成尽可能多的工作时设置它很高兴吗?

答案 2 :(得分:0)

根据我的理解,你需要这样的东西:

private static final BlockingQueue<String> queue = new LinkedBlockingQueue<String>();

private static boolean needMore = true;

static class Consumer implements Runnable
{
    Scanner scanner = new Scanner(System.in);

    @Override
    public void run()
    {           
        do
        {
            try
            {
                String s = queue.take();

                System.out.println("Got " + s);

                needMore = scanner.nextBoolean();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        while (needMore);
    }       
}

static class Producer implements Runnable
{
    Random rand = new Random();

    @Override
    public void run()
    {
        System.out.println("Starting new producer...");

        do
        {
            queue.add(String.valueOf(rand.nextInt()));

            try
            {
                Thread.sleep(1000);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        while (needMore);

        System.out.println("Producer shuts down.");
    }       
}

public static void main(String[] args) throws Exception
{        
    Thread producer1 = new Thread(new Producer());
    Thread producer2 = new Thread(new Producer());
    Thread producer3 = new Thread(new Producer());

    Thread consumer = new Thread(new Consumer());

    producer1.start();
    producer2.start();
    producer3.start();

    consumer.start();

    producer1.join();
    producer2.join();
    producer3.join();
    consumer.join();

    return;
}

消费者动态地决定它是否需要更多数据并在找到它正在搜索的内容时停止;例如;这是由用户输入真/假来继续/停止来模拟的。

这是一个I / O示例:

Starting new producer...
Starting new producer...
Starting new producer...
Got -1782802247
true
Got 314306979
true
Got -1787470224
true
Got 1035850909
false
Producer shuts down.
Producer shuts down.
Producer shuts down.

答案 3 :(得分:0)

第一眼看上去可能看起来不干净,但我觉得它实际上比拥有额外的变量更干净,如果你试图在关机过程中这样做。

让您的消费者成为ExecutorService,并在您的消费者任务中,当任务决定消费者已经消费足够时,请致电shutdownNow()。这将取消队列中的所有待处理任务,中断当前正在运行的任务,生成器将在提交时开始获取RejectedExecutionException。您可以将此异常视为来自消费者的信号。

唯一需要注意的是,当您有多个消费者时,以串行方式调用shutdownNow()并不能保证在一个消费者认为足够之后不会执行任务。我假设那很好。如果您需要此保证,那么您确实可以共享AtomicBoolean并让所有生产者和消费者检查它。