介绍
Fork/Join 是jdk1.7 提供的任务处理框架,主要思想是把线程任务分割成多个子线程进行处理,然后把子线程合并,最后得到处理结果,也是也就是分而治之的思想。
在Fork/Join的过程中,有一中工作思想叫做“工作窃取”。
工作窃取(work-stealing)的主要思想,是在多核环境中,把主任务分割成多个子任务,交给多个CPU去处理,当有CUP处于闲置的状态的时候,就会窃取其他CPU的子任务,这样可以大大的提高整体的工作效率。
下面简单编写一个例子:
主要组件
上面简单介绍了 Fork/Join 的使用方式,下面简单介绍一下主要的组件。
主要组件:
名称 | 用途 |
ForkJoinPool | 用于处理和维护Fork/Join的任务,以及整个任务调度流程 |
ForkJoinTask | 核心实现接口,用于Fork分批执行和结果Join |
ForkJoinWorkerThread | 运行Fork子任务的线程 |
WorkQueue | 存放子任务的队列 |
1、ForkJoinPool
ForkJoinPool 是JDK1.7之后,也在线程池家族中。主要作用是用户管理线程、执行fork的子任务、管理和创建任务队列和工作线程。
创建方式有两种
① ForkJoinPool.commonPool(); 使用工具类直接创建了线程池
② 直接用构造方法进行初始化
各参数含义:
名称 | 含义说明 |
parallelism | 并行级别, 默认为CPU核心数 |
factory | 工作线程工厂 |
handler | 异常处理器 |
mode | 调度模式: true表示FIFO_QUEUE; false表示LIFO_QUEUE Fork/Join 下,每个线程都有自己的工作队列。 FIFO_QUEUE模式:表明线程工作队列 先进先出 LIFO_QUEUE模式:表示线程工作队列 后进先出 |
workerNamePrefix | 工作线程的名称前缀 |
线程池提供了三个方法进行任务提交
① invoke:直到线程执行完毕才返回。同步有结果。
② execute:提交万直接返回。异步无结果。
③ submit:提交直接返回。异步有结果。(Future模式)
2、ForkJoinTask
ForkJoinTask 实现Fork/Join的核心方法,如果想实现必须集成该方法,JDK提供了两个实现类,分别是
① RecursiveAction : 无返回结果
② RecursiveTask : 有返回结果
3、ForkJoinWorkerThread
ForkJoinWorkerThread 是Fork/Join框架的线程实现,每个线程都有自己的队列,同时会注册到对应的线程池中。
队列的工作模式,取决于初始化线程池的mode字段,当队列没有工作任务的时候,就会窃取其他线程的任务。
4、WorkQueue
WorkQueue是一个双向队列,当线程在处理自己任务的时候,使用LIFO方式取任务,而窃取其他线程的任务的时候,使用FIFO方式。
queue,该队列中的任务全部由其它线程提交(也就是非工作线程调用execute/submit/invoke或者FutureTask.fork方法)。
总结:
Fork/Join框架是采用分而治之、工作窃取的模式,来提高整个任务处理效率。简单总结一下处理流程:
1、每个线程都有自己的双向队列,里面存放需要执行的任务
2、当自己线程的队列为 null 的时候,就会尝试窃取其他线程中队列的任务
3、当所有线程空闲了,就会等待上层线程进行最后的调用
参考文献 传送门