Java Producer使用者-为什么不使用简单的FixedThreadPool?

时间:2019-06-19 13:53:50

标签: java multithreading runnable executorservice

我正在阅读一些有关Java生产者使用者实现的信息。 示例中的大多数在线代码都通过以下基本对象显示了解决方案:

用作数据管道的阻塞队列

n个已将消息推送到队列中的生产者

n个正在从队列中轮询数据的使用者

通常,使用者将被提交到线程池中,以完成实现。

我研究过的另一个选项,它几乎没有在线表示形式,只是将任务作为可运行对象提交到FixedThreadPool。
在此实现中,用于处理消息的业务逻辑是在Runnable对象的run()方法中实现的。当我们有一条新消息要处理时,我们可以简单地向FixedThreadPool提交该类型的新任务,就这样。正在运行的线程数由FixedThreadPool实现以及轮询消息的逻辑来管理,我们剩下要做的就是用例的业务逻辑。
谁能解释为什么这个解决方案被忽视了?
当Java语言已经为我们实现阻塞队列并轮询时,是否有任何特定原因?

public class ProducerConsumerExample{

    private ExecutorService pool;

    public ProducerConsumerExample(int numberOfThreads){
        this.pool = Executors.newFixedThreadPool(numberOfThreads);
    }

    public void submit(MessageObject msg){
        pool.submit(new MessagePrinter(msg));
    }

}

public class MessagePrinter implements  Runnable{
    private MessageObject msg;

    public MessagePrinter(MessageObject msg){
        this.msg = msg;
    }

    @Override
    public void run() {
        //only need to implement logic that is releavent for our use case
        System.out.println("Message recieved " + msg.toString());
    }
}

public static void main(String[] args){
    ProducerConsumerExample ex = new ProducerConsumerExample(5);
    for(int i=0;i<WHATEVER;i++){
        ex.submit(new MessageObject());
    }
}

2 个答案:

答案 0 :(得分:0)

您的方法没有什么问题,只是不明显Executors.newFixedThreadPool().创建的池中使用了什么队列?如果任务数量变得可观,您确定无法获得RejectedExecutionException吗?

因此,最好使用具有预定义大小的任务队列的新的显式创建。 查看Executors.newFixedThreadPool(int)的源代码。

答案 1 :(得分:0)

实际上,最好在生产者-消费者应用程序中使用线程池。来自Java Concurrency in Practice:

  

Executor基于生产者-消费者模式,其中活动   提交任务的是生产者(   完成),执行任务的线程是使用者(使用者   这些工作单元)。使用执行器通常是最简单的方法   在您的应用程序中实现生产者-消费者设计。

选择实现时应考虑的事项:

  • 耦合:生产者和消费者之间相互了解的程度以及与渠道将他们联系在一起的渠道了解多少?
  • 底层队列实现:哪种类型的Queue最适合这项工作?
  • 生命周期:如果ThreadPool损坏或关闭会怎样?
  • 线程管理和饥饿:您需要多少精力来管理线程?长寿还是短寿?