目录
CompletableFuture
CompleteableFuture实现了2个接口,Future、CompletionStage:
- Future,在将来返回一个结果。
- CompletionStage,可以在对象完成任务以后,执行额外的异步任务。
3种使用CompletableFuture类的方法:
- 主动创建CompletableFuture对象,使其作为两个任务之间的同步点。 A任务创建一个值,该值作为Completable对象complete()方法的参数,这个值将被包装在CompletableFuture中返回,B任务调用CompletableFuture的get()或join()方法等待该值(即同步)
- 通过CompletableFuture类的静态方法runAsync(Runable runable)和supplyAsync(Supplier supplier)。方法返回CompletableFuture对象,在任务结束运行以后,对象进入完备态。(Supplier的返回值就是CompletableFuture对象完备态的值。)
- 附加声明的任务,在一个或者N个CompletableFuture对象执行完毕后,再进行异步执行,这些任务可以实现Runable,Function,Comsumer或BiConsumer(2个参数)。
一、主函数
package xyz.jangle.thread.test.n3_8.completablefuture;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
* 3.8 CompletableFuture 异步地完成和关联任务
*
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月14日 下午7:21:58
*
*/
public class M {
public static void main(String[] args) {
System.out.println("Main:start");
// 1、实例化一个CompletableFuture对象
CompletableFuture<Integer> seedFuture = new CompletableFuture<>();
Thread seedThread = new Thread(new SeedGenerator(seedFuture));
seedThread.start();
System.out.println("开始获取seed");
int seed = 0;
try {
seed = seedFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("Main: seed = " + seed);
System.out.println("Main: 开始创建数字列表");
NumberListGenerator task = new NumberListGenerator(seed);
// 2、使用CompletableFuture的supplyAsync方法来创建CompletableFuture对象(使用1的结果)
CompletableFuture<List<Long>> startFuture = CompletableFuture.supplyAsync(task);
System.out.println("Main:第一步");
// 2.1、使用completableFuture和lambda表达式异步执行任务,计算最接近1000的值
CompletableFuture<Long> step1Future = startFuture.thenApplyAsync(list -> {
System.out.println(Thread.currentThread().getName() + "任务1、最接近1000的数");
long selected = 0;
long selectedDistance = Long.MAX_VALUE;
long distance;
for (Long number : list) {
distance = Math.abs(number - 1000);
if (distance < selectedDistance) {
selected = number;
selectedDistance = distance;
}
}
System.out.println(Thread.currentThread().getName() + "任务1、计算结果:" + selected);
return selected;
});
System.out.println("Main:第二步");
// 2.2、使用CompletableFuture和lambda表达式异步执行任务,计算最大值
CompletableFuture<Long> step2Future = startFuture.thenApplyAsync(list -> {
System.out.println(Thread.currentThread().getName() + "任务2、开始计算最大值");
return list.stream().max(Long::compare).get();
});
// 2.2.1、对2.2的计算结果进行异步地输出
CompletableFuture<Void> write2Future = step2Future.thenAccept(result -> {
System.out.println(Thread.currentThread().getName() + "任务2、最大值结果:" + result);
});
System.out.println("Main:第三步");
NumberSelector numberSelector = new NumberSelector();
// 2.3、使用CompletableFuture和Function对象异步执行任务
CompletableFuture<Long> step3Future = startFuture.thenApplyAsync(numberSelector);
System.out.println("Main:等待这3步任务完成");
CompletableFuture<Void> waitFuture = CompletableFuture.allOf(step1Future, write2Future, step3Future);
CompletableFuture<Void> finalFuture = waitFuture.thenAcceptAsync(p -> {
System.out.println(Thread.currentThread().getName() + "Main:案例结束");
});
finalFuture.join();
}
}
二、种子任务
生成1-10之间的数
package xyz.jangle.thread.test.n3_8.completablefuture;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* 生成1-10之間的數字,然後調用complete()方法完成completableFuture。
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月14日 下午7:25:10
*
*/
public class SeedGenerator implements Runnable {
private CompletableFuture<Integer> resultCommunicator;
public SeedGenerator(CompletableFuture<Integer> resultCommunicator) {
super();
this.resultCommunicator = resultCommunicator;
}
@Override
public void run() {
System.out.println("生成种子");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
int seed = (int) Math.rint(Math.random()*10);
System.out.println("seed:"+seed);
resultCommunicator.complete(seed);
}
}
三、生成一个数值列表的任务
package xyz.jangle.thread.test.n3_8.completablefuture;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* 实现一个供应商类,供应一个几百万条记录的列表
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月14日 下午7:50:30
*
*/
public class NumberListGenerator implements Supplier<List<Long>> {
private final int size;
public NumberListGenerator(int size) {
super();
this.size = size;
}
@Override
public List<Long> get() {
var ret = new ArrayList<Long>();
System.out.println(Thread.currentThread().getName() + "NumberList 开始生产...");
for (int i = 0; i < size * 1000000; i++) {
long number = Math.round(Math.random() * Long.MAX_VALUE);
ret.add(number);
}
System.out.println(Thread.currentThread().getName() + "NumberList 完成生产...");
return ret;
}
}
四、计算最大值和最小值的平均值的子任务
package xyz.jangle.thread.test.n3_8.completablefuture;
import java.util.List;
import java.util.function.Function;
/**
* 根据List,计算出最大值和最小值的平均值
*
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月14日 下午8:21:12
*
*/
public class NumberSelector implements Function<List<Long>, Long> {
@Override
public Long apply(List<Long> t) {
System.out.println(Thread.currentThread().getName() + "任务3、开始计算最大值和最小值的平均值");
Long max = t.stream().max(Long::compare).get();
Long min = t.stream().min(Long::compare).get();
Long avg = (max + min) / 2;
System.out.println(Thread.currentThread().getName() + "任务3、完成计算最大值和最小值的平均值");
return avg;
}
}
五、执行结果
- 3个任务都必须等待数字列表生产完成才开始执行。
- 数字列表需要等待种子任务完成,才能开始生产列表(等待seed的值完成)
- 因为每个任务是独立的线程,所以主线程的打印信息(Main:信息)先被执行了。
Main:start
开始获取seed
生成种子
seed:10
Main: seed = 10
Main: 开始创建数字列表
Main:第一步
ForkJoinPool.commonPool-worker-3NumberList 开始生产...
Main:第二步
Main:第三步
Main:等待这3步任务完成
ForkJoinPool.commonPool-worker-3NumberList 完成生产...
ForkJoinPool.commonPool-worker-5任务3、开始计算最大值和最小值的平均值
ForkJoinPool.commonPool-worker-7任务2、开始计算最大值
ForkJoinPool.commonPool-worker-3任务1、最接近1000的数
ForkJoinPool.commonPool-worker-3任务1、计算结果:322166940672
ForkJoinPool.commonPool-worker-7任务2、最大值结果:9223371571738215424
ForkJoinPool.commonPool-worker-5任务3、完成计算最大值和最小值的平均值
ForkJoinPool.commonPool-worker-5Main:案例结束