使用LinkedBlockingQueue的ExecutorService与ThreadPoolExecutor

时间:2013-04-23 05:53:24

标签: java multithreading executorservice blockingqueue threadpoolexecutor

我正在开发一个多线程项目,我需要生成多个线程来测量客户端代码的端到端性能,因为我正在进行负载和性能测试。所以我创建了以下使用ExecutorService

的代码

以下是ExecutorService的代码:

public class MultithreadingExample {

    public static void main(String[] args) throws InterruptedException {

        ExecutorService executor = Executors.newFixedThreadPool(20);
        for (int i = 0; i < 100; i++) {
            executor.submit(new NewTask());
        }

        executor.shutdown();
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
    }
}

class NewTask implements Runnable {

    @Override
    public void run() {
        //Measure the end to end latency of my client code
    }   
}

问题陈述:

现在我正在阅读互联网上的一些文章。我发现还有ThreadPoolExecutor。所以我很困惑应该使用哪一个。

如果我将以上代码替换为:

ExecutorService executor = Executors.newFixedThreadPool(20);
    for (int i = 0; i < 100; i++) {
        executor.submit(new NewTask());
    }

为:

BlockingQueue<Runnable> threadPool = new LinkedBlockingQueue<Runnable>();

ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L, TimeUnit.MILLISECONDS, threadPool);

tpExecutor.prestartAllCoreThreads();

    for (int i = 0; i < 100; i++) {
        tpExecutor.execute(new NewTask());
    }

这会有什么不同吗?我想了解使用ExecutorService的原始代码与使用ThreadPoolExecutor粘贴的新代码之间的区别。我的一些队友说第二个(ThreadPoolExecutor)是正确的使用方式。

有人可以为我澄清这个吗?

6 个答案:

答案 0 :(得分:70)

以下是Executors.newFixedThreadPool的来源:

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

如上所示,它在内部使用ThreadPoolExecutor类和默认配置。现在有些情况下默认配置不合适而不是LinkedBlockingQueue需要使用优先级队列等。在这种情况下,调用者可以通过实例化并将所需的配置传递给它来直接处理底层ThreadPoolExecutor

答案 1 :(得分:23)

  

那会有什么不同吗?

它会使你的代码变得更加复杂而没什么好处。

  

我试图了解使用ExecutorService的原始代码与使用ThreadPoolExectuor粘贴的新代码之间有什么区别?

几乎没有。 Executors创建一个ThreadPoolExecutor来完成实际工作。

  

我的一些队友说第二个(ThreadPoolExecutor)是正确的使用方法吗?

仅仅因为它更复杂并不意味着它是正确的做法。设计人员提供了Executors.newXxxx方法,使您的生活更简单,因为他们希望您使用这些方法。我建议你也使用它们。

答案 2 :(得分:11)

  1. Executors#newFixedThreadPool(int nThreads)

    ExecutorService executor = Executors.newFixedThreadPool(20);
    
  2. 基本上是

     return new ThreadPoolExecutor(20, 20,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    

    2

    BlockingQueue<Runnable> threadPool = new LinkedBlockingQueue<Runnable>();
    ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L,
        TimeUnit.MILLISECONDS, threadPool);
    

    在第二种情况下,你只是将maxPoolSize增加到2000,我怀疑你需要它。

答案 3 :(得分:4)

我相信RejectionHandler还有一个优势。如果错了,请纠正我

答案 4 :(得分:2)

在第一个示例中,您使用以下语句

创建了仅20个线程
ExecutorService executor = Executors.newFixedThreadPool(20);

在第二个示例中,您已将线程限制范围设置在20 to 2000

之间
 ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L, 
                                     TimeUnit.MILLISECONDS,threadPool);

有更多线程可供处理。但是您已将任务队列配置为无界队列。

如果您定制了以下许多或所有参数,

ThreadPoolExecutor会更有效。

ThreadPoolExecutor(int corePoolSize, 
               int maximumPoolSize, 
               long keepAliveTime, 
               TimeUnit unit, 
               BlockingQueue<Runnable> workQueue, 
               ThreadFactory threadFactory,
               RejectedExecutionHandler handler)
设置RejectedExecutionHandler时,

max capacity for workQueue会很有用,并且已提交给Executor的任务数量超过workQueue容量。

有关详细信息,请查看ThreadPoolExecutor中的已拒绝任务部分。

答案 5 :(得分:1)

GC out of memory exception 2天后,ThreadPoolExecutor救了我的命。 :)

巴拉吉说,

  

[..] RejectionHandler还有一个优势。

在我的情况下,我有很多RejectedExecutionException并指定(如下)丢弃政策解决了我所有的问题。

private ThreadPoolExecutor executor = new ThreadPoolExecutor(1, cpus, 1, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());

但要小心!仅当您需要执行所有您提交给执行者的主题时,它才有效。

有关ThreadPoolExecutor的更多信息,请查看Darren's answer