Java中常见的普通线程池与ForkJoinPool对比

线程池的介绍可以参考我的另一篇文章《Java中线程创建方式》中有提及,这里就不详细赘述,这里主要是对比普通线程与ForkJoinPool的对比。

一、ForkJoinPool

第一次遇见ForkJoinPool还是在Java8的并行流中,并行流的原理就是通过ForkJoinPool创建处理器数目相同(实际上是内核数再减一就是最大线程数)的线程处理并发。话说ForkJoinPool类还是挺复杂的,这里就先简单介绍,后续随着学习深入再进行补充。

1.简介
  ForkJoinPool 是JDK 7加入的一个线程池类,在java.util.concurrent 包中。Fork/Join 技术是分治算法(Divide-and-Conquer)的并行实现,它是一项可以获得良好的并行性能的简单且高效的设计技术。目的是为了帮助我们更好地利用多处理器带来的好处,使用所有可用的运算能力来提升应用的性能。我们常用的数组工具类 Arrays 在JDK 8之后新增的并行排序方法(parallelSort)就运用了 ForkJoinPool 的特性,还有 ConcurrentHashMap 在JDK 8之后添加的函数式方法(如forEach等)也有运用。

2.Fork-join任务运行机制
在这里插入图片描述
3.算法介绍
(1)分治算法(Divide-and-Conquer)
  把任务递归的拆分为各个子任务,这样可以更好的利用系统资源,尽可能的使用所有可用的计算能力来提升应用性能。
(2)work-stealing(工作窃取)算法
  线程池内的所有工作线程都尝试找到并执行已经提交的任务,或者是被其他活动任务创建的子任务(如果不存在就阻塞等待)。这种特性使得 ForkJoinPool 在运行多个可以产生子任务的任务,或者是提交的许多小任务时效率更高。尤其是构建异步模型的 ForkJoinPool 时,对不需要合并(join)的事件类型任务也非常适用。

总结
  在 ForkJoinPool 中,线程池中每个工作线程(ForkJoinWorkerThread)都对应一个任务队列(WorkQueue),工作线程优先处理来自自身队列的任务(LIFO或FIFO顺序,参数 mode 决定),然后以FIFO的顺序随机窃取其他队列中的任务。

可参考:https://www.jianshu.com/p/32a15ef2f1bf

二、Java中的线程池

这里内容就简单介绍,具体可参考我其他关于线程的文章,需要先了解创建线程池的工厂类:Executors。

1.四种常见的基本线程底层都是调用的new ThreadPoolExcutor()
Executors.newFixedThreadPool(nThreads):创建固定大小的线程池。
Executors.newCachedThreadPool():无限线程池。
Executors.newSingleThreadExecutor():创建单个线程的线程池。
Executors.newScheduledThreadPool():创建跑定时任务的线程池。

2.线程池的执行流程
(1)当任务提交到线程池时,假如当前线程数小于核心线程数,直接创建线程执行,并且不会销毁,直到达到核心线程数。
(2)当核心线程都在执行还有任务提交时,任务放在阻塞队列中。
(3)阻塞队列也满了以后,继续创建线程执行任务,直到达到最大线程数。
(4)最大线程也满了以后,执行对应的拒绝策略。
(5)当线程空闲下来以后,线程在达到线程空闲等待时间后销毁,直至数量降低至核心线程数。

3.线程池相关UML简要类图关系
在这里插入图片描述

4.Executor和ExecutorService的区别
ExecutorService 接口继承了 Executor 接口,是 Executor 的子接口

ExecutorExecutorService
Executor 是 Java 线程池的核心接口,用来并发执行提交的任务ExecutorService 是 Executor 接口的扩展,提供了异步执行和关闭线程池的方法
提供execute()方法用来提交任务提供submit()方法用来提交任务
execute()方法无返回值submit()方法返回Future对象,可用来获取任务执行结果
Executor 接口定义了 execute()方法用来接收一个Runnable接口的对象ExecutorService 接口中的 submit()方法可以接受Runnable和Callable接口的对象
不能取消任务可以通过Future.cancel()取消pending中的任务
没有提供和关闭线程池有关的方法提供了关闭线程池的方法shutdown()

5.Executors和ThreadPoolExecutor区别
Executors类和ThreadPoolExecutor都是util.concurrent并发包下面的, Executos下面的newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor、newCachedThreadPool底线的实现都是用的ThreadPoolExecutor实现的,所以ThreadPoolExecutor更加灵活。

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

//newFixedThreadPool
    public newFixedThreadPool(int corePoolSize,//核心线程数
                              int maximumPoolSize,//最大线程数
                              long keepAliveTime,//空闲存活时间
                              TimeUnit unit,//单位
                              BlockingQueue<Runnable> workQueue,//队列
                              RejectedExecutionHandler handler) {//拒绝策略
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
是的,ForkJoinPoolJava的一个线程池,主要用于执行分治任务。它是Java 7引入的一个新特性,可以利用多核处理器提高并行计算性能。ForkJoinPool使用工作窃取算法,即当一个线程的任务执行完后,它会从其他线程的任务队列窃取任务来执行,以保证各个线程的任务负载较为均衡。 ForkJoinPool的使用方法与其他线程池类似,可以通过构造函数或者静态工厂方法来创建线程池。例如: ``` ForkJoinPool pool = new ForkJoinPool(); ``` 这样就创建了一个默认的ForkJoinPool线程池,它的线程数等于CPU核心数。也可以通过构造函数来指定线程池的参数,例如: ``` ForkJoinPool pool = new ForkJoinPool(4); ``` 这样就创建了一个包含4个线程的ForkJoinPool线程池。在使用ForkJoinPool时,需要定义一个ForkJoinTask任务,例如: ``` class MyTask extends RecursiveTask<Integer> { protected Integer compute() { // 执行任务 } } // 创建任务 MyTask task = new MyTask(); // 执行任务 int result = pool.invoke(task); ``` 这里的MyTask是一个继承自ForkJoinTask的任务,它的compute()方法定义了任务的具体执行过程。执行任务的方式是通过ForkJoinPool的invoke()方法来调用,它会返回任务的执行结果。 当然,除了invoke()方法之外,ForkJoinPool还提供了其他一些方法来执行任务,例如submit()和execute()方法。同时,ForkJoinPool也支持设置线程池的一些属性,例如任务窃取的策略、线程池的名称等。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值