ExectuorService与ThreadPoolExecutor(使用LinkedBlockingQueue)
我正在开发一个Multithreaded项目,在该项目中,我需要生成多个线程来测量我的客户端代码的端到端性能,因为我正在进行负载和性能testing。 所以我创build了下面使用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
也是如此。 所以我很困惑我应该使用哪一个。
如果我从我的上面的代码replace –
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
原始代码和我使用ThreadPoolExectuor
粘贴的新代码之间有什么区别? 我的一些队友说第二个(ThreadPoolExecutor)是正确的使用方法?
任何人都可以为我澄清这件事吗? 谢谢您的帮助。
这里是Executors.newFixedThreadPool
的来源:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
它在内部使用具有默认configuration的ThreadPoolExecutor
类,如上所见。 现在有些情况下,默认configuration不适合,而不是LinkedBlockingQueue
需要使用优先级队列等。在这种情况下,调用者可以通过实例化并传递所需的configuration直接在底层的ThreadPoolExecutor
上工作。
那么这将有所作为?
这会让你的代码更加复杂,而且收益不大。
我想了解我使用ExecutorService的原始代码和我使用ThreadPoolExectuor粘贴的新代码之间有什么区别?
一无所有 Executors
创build一个ThreadPoolExecutor来完成真正的工作。
我的一些队友说第二个(ThreadPoolExecutor)是正确的使用方法?
仅仅因为它更复杂并不意味着这是正确的事情。 devise人员提供了Executors.newXxxx方法,使您的生活更简单,因为他们期望您使用这些方法。 我build议你也使用它们。
-
执行者#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,我怀疑你会需要。
我相信RejectionHandler还有一个好处。 纠正我,如果错了
经过2天GC out of memory exception
, ThreadPoolExecutor
救了我一命。 🙂
巴拉吉说,
RejectionHandler还有另一个优势。
在我的情况下,我有很多RejectedExecutionException
并指定(如下)丢弃策略解决了我所有的问题。
private ThreadPoolExecutor executor = new ThreadPoolExecutor(1, cpus, 1, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());
不过要小心! 只有当你不需要执行你提交给执行者的所有线程时,它才能工作。
有关ThreadPoolExecutor
更多信息,请查看Darren的答案
在第一个例子中,你用下面的语句创build了20个线程
ExecutorService executor = Executors.newFixedThreadPool(20);
在第二个示例中,您已将线程限制范围设置在20 to 2000
之间
ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L, TimeUnit.MILLISECONDS,threadPool);
更多的线程可用于处理。 但是您已将任务队列configuration为无限队列。
ThreadPoolExecutor会更有效,如果你已经定制了许多或全部下面的参数。
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
当您max capacity for workQueue
设置max capacity for workQueue
时, RejectedExecutionHandler
将会很有用,并且已经提交给Executor的任务数量大于workQueue
容量。
查看ThreadPoolExecutor中的Rejected tasks部分以获取更多详细信息。