JAVA 递归线程池测试 ExecutorService / ForkJoinPool

 

测试工具使用递归的方式获取子进程的Msg消息,目前有2种常用的ExecutorService / ForkJoinPool

为了测试哪种效果较好,我们来写个测试Demo,循环5555555次+1(加锁),统计每种执行耗时

 

int nCpu = Runtime.getRuntime().availableProcessors();

ExecutorService executorPool  = Executors.newFixedThreadPool(nCpu);
ForkJoinPool forkJoinPool = new ForkJoinPool(nCpu);

 

TestData:5555555 , RunTime:1543 ms :ExecutorService executorPool

TestData:5555555 , RunTime:746 ms :ForkJoinPool forkJoinPool

结果很明显,递归线程池使用ForkJoinPool更佳,2倍的执行效率

 

测试流程图

 

 

 

package test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;

/**
 *
 * @author weimjsam
 */
public class TestThrad {

    public int addNum = 0;

    //get cpu 
    int nCpu = Runtime.getRuntime().availableProcessors();

    //Thread
    ExecutorService taskPush = Executors.newFixedThreadPool(nCpu);
    ExecutorService executorPool = Executors.newFixedThreadPool(nCpu);
    ForkJoinPool forkJoinPool = new ForkJoinPool(nCpu);

    private void TaskPush(int iTestAdd) {
        CompletableFuture.runAsync(() -> {

            for (int i = 0; i < nCpu; i++) {
                CompletableFuture.runAsync(() -> TestRun(iTestAdd), forkJoinPool);
            }

        }, taskPush);
    }

    private void TestRun(int iTestAdd) {
        CompletableFuture.runAsync(() -> TestAdd(iTestAdd), forkJoinPool)
                .thenRun(() -> CheckOver(iTestAdd));
    }

    private void TestAdd(int iTestAdd) {
        synchronized (this) {
            if (addNum < iTestAdd) {
                addNum = addNum + 1;
            }
        }
    }

    private void CheckOver(int iTestAdd) {
        if (addNum < iTestAdd) {
            TestRun(iTestAdd);
        }
    }

    public void Test(int iTestMax) {
        TaskPush(iTestMax);
    }

}

 

 

 

 

 

 

 

 

 

https://dwz.cn/0eWL012M

### ForkJoinPool与自定义线程池的性能对比及适用场景 #### 一、ForkJoinPool的特点及其优势 ForkJoinPool是一种专门设计用于处理大量细粒度任务的线程池,其核心思想是通过分治法(Divide and Conquer)来分解大任务为多个子任务并行执行。这种机制特别适合于可以被拆分为更小子任务的工作负载。 - **工作窃取算法**:ForkJoinPool采用了工作窃取(Work Stealing)算法,在某些线程完成自己的任务后会主动寻找其他线程的任务队列中的任务进行处理[^1]。这种方式能够有效减少线程空闲时间,提高CPU利用率。 - **高效的任务调度**:由于ForkJoinPool内部维护了一个双端队列(Deque),每个线程都有独立的任务队列,因此减少了锁竞争的概率,从而提升了整体性能[^2]。 - **适用于计算密集型任务**:对于那些可以通过递归方式分割成较小部分的大规模数据集上的复杂运算来说,比如矩阵乘法、快速傅里叶变换等,ForkJoinPool表现尤为出色[^3]。 #### 二、自定义线程池的优势 尽管ForkJoinPool具有上述优点,但在实际开发过程中也存在局限性,而传统的自定义线程池则提供了更大的灵活性: - **定制化程度高**:开发者可以根据业务需求精确控制线程数量、排队策略以及其他行为特性。例如,`ThreadPoolExecutor`允许指定拒绝策略(Rejected Execution Handler)、保持活动时间和最大池大小等参数。 - **支持多种类型的任务**:除了简单的Runnable接口外,还可以轻松集成Callable/Future模式实现异步调用返回结果的功能;同时也能很好地兼容定时任务的需求。 - **更好的调试体验**:相比于高度优化但相对复杂的ForkJoinPool结构而言,普通的Executors工厂创建出来的固定大小或者缓存型线程池往往更容易理解和追踪潜在问题所在之处[^4]。 #### 三、两者之间的主要差异总结如下表所示 | 特性 | ForkJoinPool | 自定义线程池 | |---------------------|---------------------------------------|----------------------------------| | 主要用途 | 计算密集型任务 | IO 密集型或其他通用任务 | | 调度机制 | 工作窃取 | FIFO/LIFO 或者优先级队列 | | 并发模型 | 基于分治的思想 | 单纯的任务分配 | | 配置选项 | 较少 | 更加灵活 | | 易用性和学习曲线 | 存在一定的门槛 | 相对简单直观 | #### 四、典型应用场景举例说明 - 如果项目涉及大量的数值计算或者是图像渲染等领域内的批量处理,则推荐采用ForkJoinPool因为它的架构非常适合此类场合下的资源最大化利用^。 - 对于网络爬虫抓取网页内容这样的I/O绑定操作或是数据库查询之类的长时间等待事件驱动流程下更适合选用常规意义上的可调整配置版图式化的标准库组件即传统意义上面提到过的那种形式化表达出来的东西. ```java // 创建一个带有两个核心线程的标准线程池实例演示代码片段 import java.util.concurrent.*; public class ThreadPoolExample { public static void main(String[] args){ ExecutorService executor = new ThreadPoolExecutor( 2, // core pool size 5, // maximum pool size 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>() ); Runnable task = () -> System.out.println("Executing Task"); for(int i=0;i<8;i++) { executor.submit(task); } ((ThreadPoolExecutor)executor).shutdown(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值