并发编程:CompletableFuture 异步地完成和关联任务

目录

CompletableFuture

一、主函数

二、种子任务

三、生成一个数值列表的任务

四、计算最大值和最小值的平均值的子任务

五、执行结果


 

CompletableFuture

CompleteableFuture实现了2个接口,Future、CompletionStage:

  • Future,在将来返回一个结果。
  • CompletionStage,可以在对象完成任务以后,执行额外的异步任务。

3种使用CompletableFuture类的方法:

  1. 主动创建CompletableFuture对象,使其作为两个任务之间的同步点。 A任务创建一个值,该值作为Completable对象complete()方法的参数,这个值将被包装在CompletableFuture中返回,B任务调用CompletableFuture的get()或join()方法等待该值(即同步)
  2. 通过CompletableFuture类的静态方法runAsync(Runable runable)和supplyAsync(Supplier supplier)。方法返回CompletableFuture对象,在任务结束运行以后,对象进入完备态。(Supplier的返回值就是CompletableFuture对象完备态的值。)
  3. 附加声明的任务,在一个或者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 [email protected]
 * @time 2020年8月14日 下午7:21:58
 * 
 */
public class M {

	public static void main(String[] args) {
		System.out.println("Main:start");
		// 1、实例化一个CompletableFuture对象
		CompletableFuture 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> startFuture = CompletableFuture.supplyAsync(task);
		System.out.println("Main:第一步");
		// 2.1、使用completableFuture和lambda表达式异步执行任务,计算最接近1000的值
		CompletableFuture 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 step2Future = startFuture.thenApplyAsync(list -> {
			System.out.println(Thread.currentThread().getName() + "任务2、开始计算最大值");
			return list.stream().max(Long::compare).get();
		});
		// 2.2.1、对2.2的计算结果进行异步地输出
		CompletableFuture 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 step3Future = startFuture.thenApplyAsync(numberSelector);
		System.out.println("Main:等待这3步任务完成");
		CompletableFuture waitFuture = CompletableFuture.allOf(step1Future, write2Future, step3Future);
		CompletableFuture 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 [email protected]
 * @time 2020年8月14日 下午7:25:10
 * 
 */
public class SeedGenerator implements Runnable {

	private CompletableFuture resultCommunicator;

	public SeedGenerator(CompletableFuture 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 [email protected]
 * @time 2020年8月14日 下午7:50:30
 * 
 */
public class NumberListGenerator implements Supplier> {

	private final int size;

	public NumberListGenerator(int size) {
		super();
		this.size = size;
	}

	@Override
	public List get() {
		var ret = new ArrayList();
		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 [email protected]
 * @time 2020年8月14日 下午8:21:12
 * 
 */
public class NumberSelector implements Function, Long> {

	@Override
	public Long apply(List 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:案例结束

 

你可能感兴趣的:(并发编程,#,JavaBase,java,并发编程)