57

我正在开发一个多线程项目,在进行负载和性能测试时,我需要生成多个线程来测量客户端代码的端到端性能。所以我创建了下面使用的代码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)是正确的使用方式。

任何人都可以为我澄清这一点吗?

4

6 回答 6

83

这里是来源Executors.newFixedThreadPool

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

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

于 2013-04-23T06:02:25.643 回答
30

那么这会有什么不同吗?

它会使您的代码变得更复杂,但几乎没有什么好处。

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

几乎没有。 Executors创建一个 ThreadPoolExecutor 来完成真正的工作。

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

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

于 2013-04-23T05:59:24.300 回答
14
  1. 执行程序#newFixedThreadPool(int nThreads)

    ExecutorService executor = Executors.newFixedThreadPool(20);
    

基本上是

 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,我怀疑您是否需要。

于 2013-04-23T06:01:36.697 回答
4

I believe one more advantage is with RejectionHandler. Correct me if wrong

于 2014-04-21T22:40:13.730 回答
3

在第一个示例中,您仅使用以下语句创建了 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)

RejectedExecutionHandlermax capacity for workQueue当您设置并且已提交给 Executor 的任务数量超过workQueue容量时会很有用。

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

于 2016-01-19T17:32:37.280 回答
1

2天后GC out of memory exceptionThreadPoolExecutor救了我的命。:)

正如巴拉吉所说,

[..] 另一个优势是 RejectionHandler。

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

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

但小心点!它仅在您不需要执行提交给执行程序的所有线程时才有效。

有关ThreadPoolExecutor查看Darren 的答案的更多信息

于 2015-11-10T10:03:36.133 回答