【问题标题】:Implementing Producer consumer pattern实现生产者消费者模式
【发布时间】:2011-10-24 11:23:18
【问题描述】:

我正在尝试编写一个邮件实用程序,将邮件放入队列中,然后由消费者线程使用。

我正在尝试实现一个典型的生产者-消费者模式,但是出了点问题。

我刚刚写了一个骨架,骨架没有按预期工作。

MailProducer.java

public class MailProducer implements Callable<Void>
 {

@Override
public Void call() throws Exception
{
    System.out.println("inside mail Producer");
    System.out.println("Thread executing = " +
                           Thread.currentThread().getName());
    return null;
}

}

MailConsumer.java

public class MailConsumer implements Callable<Void>
{

@Override
public Void call() throws Exception
{
    System.out.println("inside mail consumer");
    System.out.println("Thread executing = " + 
                        Thread.currentThread().getName());
    return null;
}

 }

最后是执行者

MailExecutor.java

  public class MailExecutor
  {

private static final int NTHREADS = 25;
private static final ExecutorService exec = 
                Executors.newFixedThreadPool(NTHREADS);

public static void main(String[] args)
{
    exec.submit(new MailConsumer());
    exec.submit(new MailProducer());

    System.out.println("inside main");

}

  }

现在,当我运行程序时,我希望它在生产者和消费者之间来回切换,以继续打印各自类中编写的内容。但相反,程序在打印以下行后挂起/不执行任何操作。出了什么问题?我错过了什么吗?

输出 ...(输出不是我的预期。出了什么问题?)

   inside mail consumer
   inside main
   Thread executing = pool-1-thread-1
   inside mail Producer
   Thread executing = pool-1-thread-2

【问题讨论】:

    标签: java multithreading concurrency producer-consumer executor


    【解决方案1】:

    您缺少共享队列。没有队列,你什么都没有。

    生产者将工作放入队列中。消费者将工作从队列中移除。使用BlockingQueue,其put()take() 方法是阻塞 调用。在不同的线程中运行生产者和消费者可以让他们在调用这些方法时安全地阻塞。

    生产者和消费者都不需要是CallableRunnable 可以。使用Executor 将它们联系在一起是个好主意。

    【讨论】:

    • 没什么大不了的,但是阻塞的方法其实就是put()和take()。如果没有空格,offer 将返回 false。
    【解决方案2】:

    ExecutorService.submit 为一次执行安排 Runnable 或 Callable。您的输出显示 MailProducer 和 MailConsumer 都执行了一次,所以一切正常。

    您应该将 Producer 和 Consumer 方法的内部放在循环中:

    import java.util.concurrent.*;
    
    public class Executor {
    
        private static final int NTHREADS = 25;
        private static final ExecutorService exec = 
            Executors.newFixedThreadPool(NTHREADS);
    
    
        public static void main(String[] args) {
            exec.submit(new MailConsumer());
            exec.submit(new MailProducer());
    
            System.out.println("inside main");  
        }
    
    
        static class MailProducer implements Runnable {
            @Override
            public void run() {
                while (true) {
                    System.out.println("inside mail Producer");
                    System.out.println("Thread executing = " +
                           Thread.currentThread().getName());
                }
           }
        }
    
        static class MailConsumer implements Runnable {
            @Override
            public void run() {
                while (true) {
                    System.out.println("inside mail Consumer");
                    System.out.println("Thread executing = " +
                           Thread.currentThread().getName());
                }
           }
        }
    }
    

    这给出了您期望的输出。

    【讨论】:

    • 虽然您的回答解决了一个重要问题,但您忽略了要点:使用 BlockingQueue 或类似的东西。
    • 是的,但原始发帖人的代码也是如此——他将其描述为骨架,所以我认为他试图先让 ThreadPool 工作,然后再实现 Producent-Consumer。
    • 是的,但这将使用两个线程,并且不需要执行器。
    【解决方案3】:
    1. 您必须使用循环,以便您的生产者/消费者代码执行多次。

    2. 您的线程不相互通信。目前您只有两个线程正在执行。查看BlockingQueue javadoc 中的示例了解如何操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 2018-08-26
      • 2015-10-12
      • 1970-01-01
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      相关资源
      最近更新 更多