【问题标题】:What are disadvantages of using ThreadPoolExecutor as queue?使用 ThreadPoolExecutor 作为队列有什么缺点?
【发布时间】:2023-03-16 14:23:01
【问题描述】:

对于常规的生产者-消费者问题,我们可以使用 ExecutorService 作为队列。它有什么缺点?效率低吗?因为创建线程的成本很高。

executor = Executors.newFixedThreadPool(90);
// This will be called many times concurrently
public void processObjectsWithFixedSetOfThreads(Foo objectToProcess) {
   //Create a new thread and submit (executor is of fixed size hence extra tasks will be queued)
   executor.submit(new ObjectProcessorWorker(objectToProcess));
}

class ObjectProcessorWorker implements Runnable() {
  public ObjectProcessorWorker(Foo obj) {
     this.obj = obj;
  }

  public void run() {
     longRunningProcess(obj);
  }

}

为什么推荐BlockingQueue 用于生产者-消费者问题,但也可以使用without that(如上所示)?

编辑

由于 ThreadPoolExecutor 内部维护 BlockingQueue,很多人没有得到区别。

在一家饼干厂,有一项任务是包装饼干。如果我是它的所有者,我有两种方法可以加快包装任务。

  1. 将饼干和包装纸放在流水线上,有10名工人在做包装工作。

    我 -> queue.put(biscuits, wrapper)

    工人 -> queue.take()

  2. 创建一个包装饼干的任务,然后将其放在流水线上,然后让 10 名工人去做。

    我 -> new Task(biscuits, wrapper)

    工人 -> task = queue.take(); do(task);

我问的是后一种的缺点。

【问题讨论】:

  • 它们根本不是一回事。执行器服务正在从队列中运行事物(它内部有一个阻塞队列,保存提交的任务);这不是队列本身。
  • @AndyTurner 我添加了一个编辑。

标签: java executorservice java.util.concurrent


【解决方案1】:

无论何时定义 ThreadPoolExecutore.. 如下所示

ExecutorService threadPoolExecutor =
        new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()
                );

如果在将任务委托给线程池时,在线程池中创建的线程少于 corePoolSize 个,则即使池中存在空闲线程,也会创建一个新线程。 p>

如果内部任务队列已满,并且 corePoolSize 线程或更多线程正在运行,但少于 ma​​ximumPoolSize 线程正在运行,则创建一个新线程来执行任务

现在如果你定义了 blocking queue... 而不是在 corePoolSize 之后,它将添加新线程到 queue... 直到达到队列的容量。 并且在 queue 溢出后,它会生成新的线程达到 ma​​ximumPoolSize。

不知道使用 ExecutorService 作为队列有什么好处。我认为没有任何缺点。

【讨论】:

    【解决方案2】:

    当您使用Executors.newFixedThreadPool(int) 创建ThreadPoolExecutor 时,您正在创建BlockingQueue:

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    

    因此,如果您以这种方式创建了一个线程池,那么您不会“没有”阻塞队列;它只是对你隐藏。

    【讨论】:

    • 我同意 BlockingQueue 是内部创建的。但是在执行new Runnable() 时,可能会由于创建线程而产生开销。但是,如果我创建 BlockingQueue&lt;Foo&gt; 则永远不会创建线程。
    • 当然不会创建线程:队列不会创建线程,它只是一个队列。
    • “无阻塞队列”表示使用内部BQ。
    猜你喜欢
    • 2018-05-16
    • 2016-05-23
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 2022-06-14
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多