在研究了过去 3 个月的各种多线程框架后,我找到了问题的答案。
执行服务
它简单易用,控制有限。你可以使用它
- 无需等待即可启动并行独立任务
- 等待完成所有任务
Callable/Runnable
当任务数量较少并且无限队列中的任务堆积不会导致内存堆积并降低系统性能时,我更喜欢这个。
它隐藏了ThreadPoolExecutor
. 它不允许使用其他参数(Bounded Queue, Rejection Handler
等微调性能),如ThreadPoolExectuor
.
线程池执行器
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
它为您提供更多控制。除了设置最小和最大线程外,您还可以设置队列大小和BlockingQueue
有界。
如果您需要以下功能,您可以提出自己的线程工厂
- 设置更具描述性的线程名称
- 设置线程守护进程状态
- 设置线程优先级
如果您的应用程序受到挂起的可运行/可调用任务数量的限制,您将通过设置最大容量来使用有界队列。一旦队列达到最大容量,您就可以定义 RejectionHandler。Java 提供了四种类型的拒绝处理程序策略。
在默认情况下ThreadPoolExecutor.AbortPolicy
,处理程序在拒绝时抛出运行时 RejectedExecutionException。
在ThreadPoolExecutor.CallerRunsPolicy
中,调用 execute 的线程自己运行任务。这提供了一种简单的反馈控制机制,可以减慢提交新任务的速度。
在ThreadPoolExecutor.DiscardPolicy
中,无法执行的任务被简单地丢弃。
在ThreadPoolExecutor.DiscardOldestPolicy
中,如果执行器没有关闭,则丢弃工作队列头部的任务,然后重试执行(可能再次失败,导致重复此操作。)
倒计时锁存器
CountDownLatch
:这个框架允许一个java线程等待,直到其他线程集完成它们的任务。
用例:
实现最大并行:有时我们希望同时启动多个线程以实现最大并行
在开始执行其他代码块之前等待 N 个线程完成
死锁检测。
本文列出了更多详细信息
ForkJoinPool
它ForkJoinPool
与 Java ExecutorService 类似,但有一点不同。这ForkJoinPool
使得任务可以轻松地将其工作拆分为更小的任务,然后将这些任务也提交给 ForkJoinPool。当空闲工作线程从繁忙的工作线程队列中窃取任务时,任务窃取发生在 ForkJoinPool 中。
public ForkJoinPool(int parallelism,
ForkJoinPool.ForkJoinWorkerThreadFactory factory,
Thread.UncaughtExceptionHandler handler,
boolean asyncMode)
Creates a ForkJoinPool with the given parameters.
参数:
并行度- 并行度级别。对于默认值,使用Runtime.availableProcessors()
.
factory - 创建新线程的工厂。对于默认值,使用 defaultForkJoinWorkerThreadFactory。
handler - 由于不可恢复的错误而终止的内部工作线程的处理程序
asyncMode - 如果为 true,则为从未加入的分叉任务建立本地先进先出调度模式。
关于主要查询:
您可以使用ExecutorService.invokeAll()
orCountDownLatch
框架或ForkJoinPool
. 所有这些框架在不同的粒度上相互补充,以控制从高级到低级的任务执行。
编辑:
查看相关的 SE 问题:
使用 ExecutorService 有什么好处?
Java 的 Fork/Join vs ExecutorService - 什么时候使用?