突然发现多线程系列的话题都跑完了:初遇,相识,大喜,久乐不厌,长乐无极,长乐未央。算算我自己的多线程相关文章:《当我们说起多线程与高并发时》《Java多线程学习笔记(一) 初遇篇》《Java多线程学习笔记(二) 相识篇》《Java多线程学习笔记(三) 甚欢篇》《Java多线程学习笔记(四) 久处不厌》《Java多线程学习笔记(五) 长乐无极》《 ThreadLocal学习笔记》今天应该是多线程学习笔记的最后一章了。在这篇文章中,应该会用到JDK中多线程的基本概念。还没有引入并发集合和并行流。我会重点介绍并发集合的实现,也就是上面文章介绍的一些基础类的原理,因为并发集合的使用和普通集合没有太大的区别,这也是下一个系列的文章,也就是源码系列文章,去年10月份开始的《当我们说起看源码时,我们是在看什么》,是时候填这个坑了,并行流还是放在了Stream系列文章中。这些文章目前大概在掘金和ThinkNo,并不统一。有空的时候把三个平台的文章统一在下面。如果你在公众号上找到了以上文章,那么迁移就大致完成了。ForkJoin模式介绍本文的主角是ForkJoin,作者是DougLea的作品。在看ForkJoinPool的时候,心血来潮想看看其他并发类的作者,然后发现下面没有包含未被发现的CountDownLatchCyclicBarrierSemaphoreThreadPoolExecutorFutureCallableConcurrentHashMapCopyOnWriteArrayList好像是JDK中的并发类库是这位老哥创建的.在看这位老哥的作品的时候,我也发现自己漏了类:Phaser,所以会另开一篇,下一个多线程系列会把Phaser补回来。.说了这么多,接下来我们来介绍一下ForkJoin。在IDEA中使用ForkJoin全局搜索,结果如下:先来看ForkJoinPool的继承类图:这里可以看到ForkJoinPool和ThreadPoolExecutor是同级的,ThreadPoolExecutor是一个线程池。我们对此很熟悉,所以我们可以推测ForkJoinPool是另一种类型的线程池。那么这种ForkJoinPool和ThreadPoolExecutor有什么区别呢?带着这个疑问,我们来看一下ForkJoinPool的注释。注意,由于ForkJoinPool和ThreadPoolExecutor都属于ExecutorService的子类,所以ForkJoinPool的注释不会说ThreadPoolExecutor是另一种线程池(ThreadPool,而是另一种形式的ExecutorService)。用于运行ForkJoinTasks的ExecutorService。ForkJoinPool为来自非ForkJoinTask客户端的提交以及管理和监视操作提供入口点。ForkJoinPool与其他类型的ExecutorService的不同之处主要在于采用工作窃取:池中的所有线程都尝试查找和执行任务提交到池和/或由其他活动任务创建(如果不存在,最终阻塞等待工作)。当大多数任务产生其他子任务(大多数ForkJoinTasks也是如此)时,以及当许多小任务从外部客户端提交到池时,这可以实现高效处理。特别是在构造函数中将asyncMode设置为true时,ForkJoinPools也可能适用于从未加入的事件式任务。所有工作线程都初始化为Thread.isDaemon设置为true.ForkJoinPool这个异常执行服务(或者译为这个ExecutorService执行一些ForkJoinTasks)执行的是ForkJoinTask(Fork:分叉、崎开两条分割)以是唯一,kJoinTask可以理解为拆分合并任务,也可以执行一些不属于该类型的任务。管理和监控操作ForkJoinPool与其他类型的ExecutorService的主要区别在于它采用了工作窃取算法:线程池中的所有线程都会尝试查找并执行提交给该线程的任务和其他未完成的任务(如果没有任务,所有线程都将处于阻塞等待状态)。这种处理方式对于一些可以将大任务切分成子任务,与其他客户端一起提交到线程池的小任务(即ForkJoin任务),这种处理方式非常高效。ForkJoinPool也可能更适合永远不需要合并结果的事件驱动型任务。所有工作线程在初始化期间都被设置为守护线程。work-stealing算法介绍在介绍work-stealing算法之前,我们先回顾一下ThreadPoolExecutor的工作模式。当客户端向线程池提交任务时,线程池会先判断当前工作线程是否小于核心线程数。如果小于核心线程数,会继续向线程添加工作线程,如果不小于核心线程数,任务会被放入任务队列,如果队列已满,则判断当前工作线程是否大于最大线程数,如果大于等于最大线程数将触发拒绝策略。//ThreadPoolExecutor的执行方法publicvoidexecute(Runnablecommand){if(command==null)thrownewNullPointerException();intc=ctl.get();//ctl可以简单理解为线程的状态数量//workerCountOf用于计算工作线程数if(workerCountOf(c)
