java Fork/Join 池、ExecutorService 和 CountDownLatch

Posted

技术标签:

【中文标题】java Fork/Join 池、ExecutorService 和 CountDownLatch【英文标题】:java Fork/Join pool, ExecutorService and CountDownLatch 【发布时间】:2015-10-13 11:23:23 【问题描述】:

我们在 java 中有三种不同的多线程技术 - Fork/Join pool、Executor Service 和 CountDownLatch

分叉/加入池 (http://www.javacodegeeks.com/2011/02/java-forkjoin-parallel-programming.html)

Fork/Join 框架旨在使分而治之的算法易于并行化。这种类型的算法非常适合可以分为两个或多个相同类型的子问题的问题。他们使用递归将问题分解为简单的任务,直到这些任务变得简单到可以直接解决。然后将子问题的解决方案组合起来,得到原始问题的解决方案

ExecutorService是一个扩展Executor类的接口,代表异步执行。它为我们提供了管理异步任务结束和检测进度的机制。

invokeAll() : 执行给定的任务,返回一个 Futures 列表,在所有完成后保存它们的状态和结果。 Future.isDone() 对于返回列表的每个元素都是 true。

CountDownLatch:(http://examples.javacodegeeks.com/core-java/util/concurrent/countdownlatch-concurrent/java-util-concurrent-countdownlatch-example/)

CountDownLatch 用于同步,以允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

我的假设:

在这两种选择中,最终结果只有在所有任务/线程完成后才能知道。

这三个选项是互补的还是互补的

【问题讨论】:

CountDownLatch 是一个通用的低级同步原语,它可以用于同步任何类型的操作,而ForkJoin 是一个更高级别的抽象,专门用于递归除/征服处理。 CountDownLatch 不是一个框架。 Biziclop 称其为“多功能”。我称它为简单的污垢。你可以用一个初始整数值构造一个,你可以递减这个值,你可以得到这个值,你可以等待这个值达到零(即,因为被其他线程递减)。这就是它的全部 【参考方案1】:

在过去 3 个月对各种多线程框架进行研究后,我找到了问题的答案。

ExecutorService

它简单易用,控制有限。你可以使用它

    无需等待即可启动并行独立任务 等待完成所有任务

Callable/Runnable 任务的数量很少并且无限队列中的任务堆积不会导致内存堆积和降低系统性能时,我更喜欢这个。

它隐藏了ThreadPoolExecutor 的低级细节。它不允许像ThreadPoolExectuor 那样使用其他参数(Bounded Queue, Rejection Handler 等来微调性能)。

ThreadPoolExecutor

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

它为您提供更多控制。除了设置最小和最大线程外,您还可以设置队列大小并使BlockingQueue 有界。

如果您需要以下功能,您可以提出自己的线程工厂

    设置更具描述性的线程名称 设置线程守护进程状态 设置线程优先级

如果您的应用程序受到待处理的可运行/可调用任务数量的限制,您将通过设置最大容量来使用有界队列。一旦队列达到最大容量,您就可以定义 RejectionHandler。 Java提供了四种Rejection Handlerpolicies。

    在默认的ThreadPoolExecutor.AbortPolicy 中,处理程序在拒绝时抛出运行时 RejectedExecutionException。

    ThreadPoolExecutor.CallerRunsPolicy 中,调用execute 的线程自己运行任务。这提供了一种简单的反馈控制机制,可以减慢新任务的提交速度。

    ThreadPoolExecutor.DiscardPolicy 中,简单地丢弃了一个无法执行的任务。

    ThreadPoolExecutor.DiscardOldestPolicy中,如果executor没有关闭,工作队列头部的任务会被丢弃,然后重试执行(可能再次失败,导致重复。)

CountDownLatch

CountDownLatch:该框架允许 java 线程等待,直到其他线程集完成它们的任务。

用例:

    实现最大并行度:有时我们希望同时启动多个线程以实现最大并行度

    等待 N 个线程完成,然后再开始执行其他代码块

    死锁检测。

更多详情列于article

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.

参数:

parallelism - 并行度。默认值,使用Runtime.availableProcessors()

factory - 创建新线程的工厂。对于默认值,使用 defaultForkJoinWorkerThreadFactory。

handler - 由于不可恢复的错误而终止的内部工作线程的处理程序

asyncMode - 如果为 true,则建立本地先进先出调度模式 对于从未加入的分叉任务。

关于主要查询:

您可以使用 ExecutorService.invokeAll()CountDownLatch 框架或 ForkJoinPool 。所有这些框架在不同的粒度上相互补充,以控制从高级别到低级别的任务执行。

编辑:

查看相关的 SE 问题:

What are the advantages of using an ExecutorService?

Java's Fork/Join vs ExecutorService - when to use which?

【讨论】:

以上是关于java Fork/Join 池、ExecutorService 和 CountDownLatch的主要内容,如果未能解决你的问题,请参考以下文章

Executor Framework分析 ForkJoinPool的使用

Executor Framework分析 ForkJoinPool的使用

java7-Fork/Join

Java多线程 6.Fork/Join

Java的Fork/Join任务

Java Fork/Join 框架