文章目录
ForkJoinPool类 JDK 1.7
ForkJoin 并发执行任务,提高效率,在大数据量表现显著。最适合的是计算密集型的任务。
ForkJoin工作原理
- 是将大量的数据分成多个子任务处理,然后合并。
ForkJoin特点
- 工作窃取:该线程的任务执行完之后,就会去窃取其他线程没有执行完的任务,把任务拿到自己这里来执行,提高效率。
- 用的双端队列
java.util.concurrent.ForkJoinPool
类继承Executor。
常用方法
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task)
提交一个ForkJoinTask来执行。
ForkJoinTask是一个抽象类方法,如果要使用ForkJoinPool去执行代码,就得继承ForkJoinTask的子抽象类去实现,然后使用ForkJoinPool的submmit方法去使用
ForkJoinTask<V> 抽象类
public final ForkJoinTask <V> fork()
把拆分任务压入到线程中public final V join()
返回计算结果
RecursiveAction 抽象类
protected abstract void compute()
这个任务执行的主要计算。
RecursiveTask<V> 抽象类
protected abstract V compute()
这个任务执行的主要计算。
LongStream 接口
-
static LongStream range(long startInclusive,long endExclusive)
返回从startInclusive(含)至 endExclusive通过增量步骤 1的最终结果。 [start,end) -
static LongStream range(long startInclusive,long endExclusive)
返回从startInclusive至 endExclusive(含)通过增量步骤 1的最终结果。 (start,end] -
LongStream parallel()
使其为并行流 -
long reduce(long identity, LongBinaryOperator op)
合并流产生的元素,并产生单个值返回。
案例 使用ForkJoin,并行Stream计算大数据的和
Recursive 递归
parallel 平行
ForkJoinDemon.java
public class ForkJoinDemon extends RecursiveTask<Long> {
private long start;
private long end;
private final long temp = 10000L; // 规定一个临界值
public ForkJoinDemon(long start, long end) {
this.start = start;
this.end = end;
}
// 递归合并
@Override
protected Long compute() {
// 如果计算的两个值在临界值以内,就直接使用for循环计算
if((end - start) < temp){
long sum = 0L;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
}else {
// 计算中间值,将其分为两个线程两个对象去进行计算,在new的新对象中,
// 也会去判断是否在临界值以内,否则还会继续new一个新对象,进入新线程中计算
long middle = (end + start)/2;
ForkJoinDemon task1 = new ForkJoinDemon(start, middle);
task1.fork(); // 把拆分任务压入到线程中
ForkJoinDemon task2 = new ForkJoinDemon(middle + 1, end);
task2.fork();
return task1.join()+task2.join(); // 将两个任务的返回值,合并在一起
}
}
}
ForkJoinTest.java
public class ForkJoinTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// test01(); // 结果:500000000500000000 时间:723
test02(); // 结果:500000000500000000 时间:641
// test03(); // 结果:500000000500000000 时间:467
}
// 普通方法for循环计算
public static void test01(){
long start = System.currentTimeMillis();
long sum = 0L;
for (int i = 1; i <= 10_0000_0000L; i++) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println("结果:" + sum + " 时间:" + (end-start));
}
// 使用ForkJoin 并行计算
public static void test02() throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
long sum = 0L;
ForkJoinPool joinPool = new ForkJoinPool();
ForkJoinDemon joinDemon = new ForkJoinDemon(0L, 10_0000_0000L);
ForkJoinTask<Long> submit = joinPool.submit(joinDemon);
sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("结果:" + sum + " 时间:" + (end-start));
}
// 使用Stream流 并行计算
public static void test03(){
long start = System.currentTimeMillis();
// 设置计算范围,增1计算,使用并行,将并行线程的值合并成一个值,返回
long sum = LongStream.rangeClosed(0, 10_0000_0000L).parallel().reduce(0, (a, b) -> a + b);
long end = System.currentTimeMillis();
System.out.println("结果:" + sum + " 时间:" + (end-start));
}
}
CompletableFuture<T>类 异步回调 JDK1.8
java.util.concurrent.CompletableFuture<T>
类,异步回调类。如同前端的Ajax。如在主线程new了该类,该类会创建一个新的线程去执行任务,并且主线程和该新线程互不影响。可同时进行。
构造方法
public CompletableFuture()
创建一个新的不完整的CompletableFuture
常用方法
public static CompletableFuture<Void> runAsync(Runnable runnable)
异步完成任务,并没有返回值public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
异步完成任务,有返回值public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
当成功完成异步任务的回调函数。public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
捕获异常,并由返回值。
public class CompletableFutureTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 没有返回值
CompletableFuture<Void> runAsync =
CompletableFuture.runAsync(() -> System.out.println("已执行runAsync 200"));
runAsync.get(); // 获取结果值,如果一直执行不完,该方法就会被阻塞,一直等待去get
// 有返回值
CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
// System.out.println(19/0);
return 200;
});
//System.out.println(supplyAsync.get());
// 当成功完成
Integer info = supplyAsync.whenComplete((t, e) -> {
System.out.println(t); // 获得成功执行完成的返回值,如果执行出错为null
System.out.println(e); // 如果执行不成功,获取异常信息,如果没有异常为null
}).exceptionally((e) -> { // 如果没有异常不执行
e.getMessage(); // 将执行失败的异常信息获取出来
return 404; // 有返回值
}).get();
System.out.println(info);
}
}
/* 输出:
已执行runAsync 200
200
null
200*/