廖雪峰Java11多线程编程-3高级concurrent包-9Fork_Join
1. Fork/Join模式
线程池可以高效执行大量小任务:
Fork/Join线程池可以执行一种特殊的任务:
- 把一个大任务拆成多个小任务并行执行
- Fork/Join是在JDK 1.7引入的
Fork/Join模式的应用:
- java.util.Arrays.parallelSort(array):方法内部通过Fork/Join对一个大数组进行并行排序,在多核CPU上就可以大大提高排序的速度。
例如:计算一个有1000万个元素数组的和。
如果把一个大数组拆成2个数组,就可以利用双核CPU并行计算,最后把2个结果相加就是最终的结果。
如果拆成2个数组以后,每个数组仍然很大,可以进一步拆分成4个数组,我们就可以让4核CPU并行执行。
Fork/Join就是把一个大任务不断的拆成小任务,执行并行计算的一种模式。
class SumTask extends RecursiveTask<Long> {
@Override
protected Long compute(){
//把一个大任务分拆成2个子任务
SumTask subtask1 = new Sumtask(...);
SumTask subtask2 = new Sumtask(...);
//调用invokeAll()同时运行2个小任务,当2个任务都完成以后,invokeAll才返回
invokeAll(subtask1, subtask2);
//通过join()获得2个子任务的结果
Long result1 = subtask1.join();
Long result2 = subtask2.join();
return result1 + result2; //返回结果
}
}
使用Fork/Join的关键在于,在compute方法内部,我们需要把一个大任务分拆成2个小任务,然后调用invokeAll()这个方法同时运行2个小任务。
当2个任务都运行结束以后,invokeAll()才会返回。接着,我们调用join()方法获得2个小任务的执行结果,最后把2个结果相加返回。
Recursive可以不断的把自身拆成小任务并行执行
2.示例
1.创建长度为1000的随机数组成的数组,并计算和作为期望值
2.使用SumTask创建一个ForkJoinTask对象。
3.通过ForkJoinPool.commonPool()方法获得一个commonPool(),然后用invoke来执行这个任务
4.求和的任务SumTask继承制RecursiveTask,返回值是Long类型,指定常量是THREHOLD。构造方法是传入一个数组、开始索引、结束索引。
5.SumTask的compute方法:我们首先判断任务是否足够的小。是,就直接进行计算,并且返回计算的结果;否,即继续拆分,这样我们就获得了subtask1,subtask2 这两个子任务。紧接着调用invokeAll()方法,同时执行这两个子任务。然后我们用join()方法获得两个子任务的结果,相加返回。
import java.awt.*;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
class SumTask extends RecursiveTask<Long> {//求和的任务继承至RecursiveTask,返回值是Long类型
//执行常量THRESHOLD,用它来分解任务
static final int THRESHOLD = 250;
long[] array;
int start;
int end;
SumTask(long[] array,int start,int end){
//创建SumTask时,传入一个数组,起始结束位置的索引
this.array = array;
this.start = start;
this.end = end;
}
public Long compute(){
//执行compute方法时,任务足够小,直接计算返回执行的结果
if(end - start <= THRESHOLD){
long sum = 0;
for(int i=start;i<end;i++){
sum += this.array[i];
try{
Thread.sleep(2);
}catch (InterruptedException e){}
}
return sum;
}
//如果任务太大,就一分为二,拆成2个子任务
int middle = (start + end) / 2;
System.out.println(String.format("split %d-%d ==> %d~%d ,%d~%d",start,end,start,middle,middle,end));
SumTask subtask1 = new SumTask(this.array,start,middle);
SumTask subtaks2 = new SumTask(this.array,middle,end);
//调用invokeAll同时执行这两个任务
invokeAll(subtask1,subtaks2);
//用join获取子任务的结果
Long subresult1 = subtask1.join();
Long subresult2 = subtaks2.join();
Long result = subresult1 + subresult2;
System.out.println(String.format("result = %d + %d ==> %d",subresult1,subresult2,result));
return result;
}
}
public class ForkJoinTaskSample {
//对一个大数组进行求和
public static void main(String[] args) throws Exception{
long[] array = new long[1000]; //创建一个包含1000个元素的数组
long expectedSum = 0;
for(int i=0;i<array.length;i++){
//1.创建数组的过程中,并计算数组的和作为期望值
array[i] = random();
expectedSum += array[i];
}
System.out.println("expectedSum: "+expectedSum);
//创建一个ForkJoinTask
ForkJoinTask<Long> task = new SumTask(array,0,array.length);
Long startTime = System.currentTimeMillis();
//通过ForkJoinPool.commonPool获得一个ForkJoinPool,用invoke方法执行这个任务
Long result = ForkJoinPool.commonPool().invoke(task);
Long endTime = System.currentTimeMillis();
System.out.println("Fork/join sum: "+result+" in "+(endTime-startTime));
}
static Random random = new Random(0);
static long random(){
return random.nextInt(10000);
}
}
3. 总结:
- Fork/Join是一种基于分治的算法:分解任务+合并结果
- Fork/JoinPool线程池可以把一个大任务拆成小任务并行执行
- 任务类必须继承自RecursiveTask/RecursiveAction。
* RecursiveTask有返回值;RecursiveAction没有返回值 - 使用Fork/Join模式可以进行并行计算提高效率
廖雪峰Java11多线程编程-3高级concurrent包-9Fork_Join的更多相关文章
- 廖雪峰Java11多线程编程-3高级concurrent包-5Atomic
Atomic java.util.concurrent.atomic提供了一组原子类型操作: 如AtomicInteger提供了 int addAndGet(int delta) int increm ...
- 廖雪峰Java11多线程编程-3高级concurrent包-4Concurrent集合
Concurrent 用ReentrantLock+Condition实现Blocking Queue. Blocking Queue:当一个线程调用getTask()时,该方法内部可能让给线程进入等 ...
- 廖雪峰Java11多线程编程-3高级concurrent包-1ReentrantLock
线程同步: 是因为多线程读写竞争资源需要同步 Java语言提供了synchronized/wait/notify来实现同步 编写多线程同步很困难 所以Java提供了java.util.concurre ...
- 廖雪峰Java11多线程编程-3高级concurrent包-6ExecutorService
Java语言内置多线程支持: 创建线程需要操作系统资源(线程资源,栈空间) 频繁创建和销毁线程需要消耗大量时间 如果可以复用一个线程 线程池: 线程池维护若干个线程,处于等待状态 如果有新任务,就分配 ...
- 廖雪峰Java11多线程编程-3高级concurrent包-8CompletableFuture
使用Future可以获得异步执行结果 Future<String> future = executor.submit(task); String result = future.get() ...
- 廖雪峰Java11多线程编程-3高级concurrent包-7Future
JDK提供了ExecutorService接口表示线程池,可以通过submit提交一个任务. ExecutorService executor = Executors.newFixedThreadPo ...
- 廖雪峰Java11多线程编程-3高级concurrent包-3Condition
Condition实现等待和唤醒线程 java.util.locks.ReentrantLock用于替代synchronized加锁 synchronized可以使用wait和notify实现在条件不 ...
- 廖雪峰Java11多线程编程-3高级concurrent包-2ReadWriteLock
ReentrantLock保证单一线程执行 ReentrantLock保证了只有一个线程可以执行临界区代码: 临界区代码:任何时候只有1个线程可以执行的代码块. 临界区指的是一个访问共用资源(例如:共 ...
- 廖雪峰Java11多线程编程-2线程同步-3死锁
1.线程锁可以嵌套 在多线程编程中,要执行synchronized块: 必须首先获得指定对象的锁 Java的线程锁是可重入的锁.对同一个对象,同一个线程,可以多次获取他的锁,即同一把锁可以嵌套.如以下 ...
随机推荐
- C++之引用与符号“&”
一.&的意思: 1.取地址符,这时候它用于数据的前面,比如int a=&b; 2.C++里还使用&作为引用符,如果你确认程序是标准的C而非C++的话,那么可以排除是引用了.引用 ...
- Delph i2010
我在习惯Delphi2010 转载 一直留着一个txt文件,不晓得是干嘛的(忘记了),偶然打开一看.乖乖~ 2010 还可以这样玩. 1.循环有了新用法 procedure TForm1.Butt ...
- ElasticSearch 命令执行漏洞(CVE-2014-3120)
POST /_search?pretty HTTP/1.1 Host: your-ip:9200 Accept: */* Accept-Language: en User-Agent: Mozilla ...
- SQLServer 安装失败可能的原因
问题:安装的时候显示参数指定的目录无效 解决:你的安装盘使用了文件/文件夹压缩功能,去掉压缩属性即可! 建议不要轻易使用储存盘的压缩功能
- 解析css3 shake 抖动样式
前端时间做项目发现一抖动按钮挺吸引眼球的,研究了下实现原理,在此和大家分享下: CSS Shake是一个使用CSS3实现的动画样式,使用SASS编写,利用它我们可以实现多种不同样式的抖动效果(如下面的 ...
- 01、requests 基本使用
requests模块的基本使用 基于网络请求的模块. 环境的安装:pip install requests 作用:模拟浏览器发起请求 分析requests的编码流程: 1.指定url 2.发起了请求 ...
- Read-Write lock 看可以,不过看的时候不能写
当线程“读取”实例的状态时,实例的状态不会改变,只有线程对实例“写入”操作时才会改变.read-write lock 模式将读取和写入分开来处理,在读取数据前获取读锁定,而写入之前,必须获取写锁定. ...
- 2019-8-31-C#-直接创建多个类和使用反射创建类的性能
title author date CreateTime categories C# 直接创建多个类和使用反射创建类的性能 lindexi 2019-08-31 16:55:58 +0800 2018 ...
- Jinja2模板引擎
这里是Jinja2通用模板语言的文档. Jinja2 在其是一个 Python 2.4 库之前,被设计 为是灵活.快速和安全的.如果你接触过其它的基于文本的模板语言,比如 Smarty 或 Djang ...
- Let's Encrypt 安装配置教程,免费的 SSL 证书
官网:https://letsencrypt.org/ 安装Let's Encrypt 安装非常简单直接克隆就可以了 git clone https://github.com/letsencrypt/ ...