java.util.concurrent.CompletableFuture

博文目录

文章目录

  • 背景
    • 异步计算
    • Future 接口的局限性
    • CompletionStage
    • CompletableFuture
  • 前置 - 函数式接口
    • Function< T, R>, apply
    • Consumer< T>, accept
    • Supplier< T>, get
    • Predicate< T>, test
    • Operator< T>, apply
    • Runnable, run
  • 初始化
    • 常规方式
    • 静态方法方式
  • 一个阶段结束再执行另一个阶段
    • whenComplete,BiConsumer
    • thenApply,Function
    • handle,BiFunction
    • thenAccept,Consumer
    • thenRun,Runnable
    • thenCompose,Function
  • 根据两个独立阶段的执行结果做不同的操作
    • thenCombine,BiFunction
    • thenAcceptBoth,BiConsumer
    • applyToEither,Function
    • acceptEither,Consumer
    • runAfterEither,Runnable
    • runAfterBoth, Runnable
  • 演示


CompletableFuture 使用详解
CompletableFuture基本用法

背景

异步计算

  • 所谓异步调用其实就是实现一个可无需等待被调用函数的返回值而让操作继续运行的方法。在 Java 语言中,简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结果。但调用者仍需要取线程的计算结果。
  • JDK5新增了Future接口,用于描述一个异步计算的结果。虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果。

Future 接口的局限性

  • Future接口可以构建异步应用,但依然有其局限性。它很难直接表述多个Future 结果之间的依赖性。实际开发中,我们经常需要达成以下目的:
  • 将多个异步计算的结果合并成一个
  • 等待Future集合中的所有任务都完成
  • Future完成事件(即,任务完成以后触发执行动作)
  • 。。。

CompletionStage

  • CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段
  • 一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())
  • 一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发

CompletableFuture

  • 在Java8中,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合 CompletableFuture 的方法。
  • 它可能代表一个明确完成的Future,也有可能代表一个完成阶段( CompletionStage ),它支持在计算完成以后触发一些函数或执行某些动作。
  • 它实现了Future和CompletionStage接口
// Future: 用于表示异步计算的结果。提供了检查计算是否完成、等待其完成以及取回计算结果的方法。T:get方法返回的结果的类型
// CompletionStage: 异步计算的某个阶段,前一个阶段完成时,该阶段开始执行操作或计算值。一个阶段在其计算终止时被称作完成,但是这个完成又可能触发其他的从属阶段。该接口定义了异步计算流程中的不同阶段间的联动操作规范
// CompletableFuture: 可以显式地完成(设置它的值和状态),可以作为CompletionStage来使用,并且支持在完成时触发依赖函数和操作的一个Future的实现
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {}

前置 - 函数式接口

函数式接口 (Functional Interface) 就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。

  • Unary: 一元, 代表一个参数
  • Binary: 二元, 代表两个参数, 同Bi

Function< T, R>, apply

表示一个有输入有输出的函数

// Function, 参数是T, 结果是R
public interface Function<T, R> {
	R apply(T t);
}
// BiFunction, 参数是T和U, 结果是R
public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}
// LongFunction, 参数是long, 结果是R
public interface LongFunction<R> {
    R apply(long value);
}
// LongToIntFunction, 参数是long, 结果是int
public interface LongToIntFunction {
    int applyAsInt(long value);
}
// LongToDoubleFunction, 参数是long, 结果是double
public interface LongToDoubleFunction {
    double applyAsDouble(long value);
}
// ToLongFunction, 参数是T, 结果是long
public interface ToLongFunction<T> {
    long applyAsLong(T value);
}
// ToLongBiFunction, 参数是T和U, 结果是long
public interface ToLongBiFunction<T, U> {
    long applyAsLong(T t, U u);
}
// 类似Long系Function的还有Int和Double两套

Consumer< T>, accept

表示一个有输入没有输出的函数

// Consumer, 参数是T, 没有返回值
public interface Consumer<T> {
    void accept(T t);
}
// BiConsumer, 参数是T和U, 没有返回值
public interface BiConsumer<T, U> {
    void accept(T t, U u);
}
// LongConsumer, 参数是long, 没有返回值
public interface LongConsumer {
    void accept(long value);
}
// ObjLongConsumer, 参数是T和long, 没有返回值
public interface ObjLongConsumer<T> {
    void accept(T t, long value);
}
// 类似Long系Consumer的还有Int和Double两套

Supplier< T>, get

表示一个没有输入有输出的函数

// Supplier, 没有参数, 结果是T
public interface Supplier<T> {
    T get();
}
// LongSupplier, 没有参数, 结果是long
public interface LongSupplier {
    long getAsLong();
}
// 类似Long系Consumer的还有Int和Double和Boolean三套

Predicate< T>, test

表示一个有输入有输出且输出是boolean类型的函数, 副词

// Predicate, 参数是T, 结果是boolean
public interface Predicate<T> {
    boolean test(T t);
}
// BiPredicate, 参数是T和U, 结果是boolean
public interface BiPredicate<T, U> {
    boolean test(T t, U u);
}
// LongPredicate, 参数是long, 结果是boolean
public interface LongPredicate {
    boolean test(long value);
}
// 类似Long系Predicate的还有Int和Double两套

Operator< T>, apply

表示一个有输入有输出且入参和结果类型相同的函数, 继承自Function

// UnaryOperator, 一元操作, 一个入参一个出参且类型都一样
public interface UnaryOperator<T> extends Function<T, T> {}
// BinaryOperator, 二元操作, 两个入参一个出参且类型都一样
public interface BinaryOperator<T> extends BiFunction<T,T,T> {}
// LongUnaryOperator, 一元操作, 一个入参一个出参且类型都是long
public interface LongUnaryOperator {
    long applyAsLong(long operand);
}
// LongBinaryOperator, 二元操作, 两个入参一个出参且类型都是long
public interface LongBinaryOperator {
    long applyAsLong(long left, long right);
}
// 类似Long系Operator的还有Int和Double两套

Runnable, run

表示一个没有输入没有输出的函数

初始化

常规方式

ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<T> future = new CompletableFuture<T>();
// 当future状态转为完成时回调该方法, value是返回值, cause是Throwable, 如果cause不是null则说明执行报错了, 否则就是正常执行 
future.whenComplete((value, cause) -> {
	log.info(null != cause ? cause.getMessage() : value);
});
// 使用线程池跑异步任务
executor.execute(() -> {
	try {
		TimeUnit.SECONDS.sleep(2);
		// future 未完成时, 设置 get 或 相关方法 的返回值对象, 并且将该 future 转为完成状态
		future.complete("SUCCESS");
	} catch (Throwable cause) {
		// future 未完成时, 设置发生异常的原因, 并且将该 future 转为完成状态
		future.completeExceptionally(cause);
	}
});
executor.shutdown();

静态方法方式

CompletableFuture 提供了四个静态方法来创建一个异步操作。

public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。

  • runAsync方法不支持返回值。
  • supplyAsync可以支持返回值。
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static final String SUCCESS = "success";

@Test
public void init() throws Throwable {

	CompletableFuture<Void> runAsyncFuture = CompletableFuture.runAsync(() -> {
		log.info("start");
		ThreadKit.sleepSecond(1);
		log.info("finish");
	});
	log.info("{}", runAsyncFuture.get());

	System.out.println();

	CompletableFuture<Void> runAsyncFutureWithExecutor = CompletableFuture.runAsync(() -> {
		log.info("start");
		ThreadKit.sleepSecond(1);
		log.info("finish");
	}, executor);
	log.info("{}", runAsyncFutureWithExecutor.get());

	System.out.println();

	CompletableFuture<String> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
		log.info("start");
		ThreadKit.sleepSecond(1);
		log.info("finish");
		return SUCCESS;
	});
	log.info("{}", supplyAsyncFuture.get());

	System.out.println();

	CompletableFuture<String> supplyAsyncFutureWithExecutor = CompletableFuture.supplyAsync(() -> {
		log.info("start");
		ThreadKit.sleepSecond(1);
		log.info("finish");
		return SUCCESS;
	}, executor);
	log.info("{}", supplyAsyncFutureWithExecutor.get());

	executor.shutdown();

}
[20210204.164541.643][INFO ][ForkJoinPool.commonPool-worker-1] start
[20210204.164542.648][INFO ][ForkJoinPool.commonPool-worker-1] finish
[20210204.164542.648][INFO ][main] null

[20210204.164542.650][INFO ][pool-2-thread-1] start
[20210204.164543.650][INFO ][pool-2-thread-1] finish
[20210204.164543.650][INFO ][main] null

[20210204.164543.653][INFO ][ForkJoinPool.commonPool-worker-1] start
[20210204.164544.653][INFO ][ForkJoinPool.commonPool-worker-1] finish
[20210204.164544.653][INFO ][main] success

[20210204.164544.654][INFO ][pool-2-thread-1] start
[20210204.164545.654][INFO ][pool-2-thread-1] finish
[20210204.164545.654][INFO ][main] success

一个阶段结束再执行另一个阶段

whenComplete,BiConsumer

当上个阶段正常结束或抛出异常的时候,接收上个阶段的结果和异常,作为入参接着执行该阶段,该阶段没有返回值(即下下个阶段如果需要拿到该阶段的结果是null)

public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)

whenComplete 和 whenCompleteAsync 的区别:

  • whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务
  • whenCompleteAsync:是把 whenCompleteAsync 这个任务提交给线程池执行。没有传入线程池使用默认线程池执行,传入线程池则使用传入的线程池执行

其他类似方法也是同样的规则

BiConsumer, 代表两个入参没有出参的函数,第一个参数是上个阶段的结果,第二个参数是上个阶段的异常。如果上个阶段正常结束,则异常为null,如果上个阶段异常,则异常不为null。如果上个阶段正常结束且没有返回值,则第一个参数为null

thenApply,Function

当上个阶段正常结束的时候,接收上个阶段的结果,作为入参接着执行该阶段,该阶段有返回值。如果上个阶段异常则该阶段不再执行

Function,代表一个入参一个出参的函数,入参是上个阶段的结果,出错的话会报异常

handle,BiFunction

和 whenComplete 一样,只是有返回值。当上个阶段正常结束或抛出异常的时候,接收上个阶段的结果和异常,作为入参接着执行该阶段,该阶段有返回值

BiFunction,代表两个入参一个出参的函数,第一个参数是上个阶段的结果,第二个参数是上个阶段的异常。

thenAccept,Consumer

和 thenApply 一样,只是没有返回值

Consumer,代表一个入参没有出参的函数,入参是上个阶段的结果

thenRun,Runnable

当上个阶段正常结束或抛出异常的时候,接着执行该阶段,不接收上个阶段的结果或异常,也不返回结果

Runnable,代表没有入参没有出参的函数

thenCompose,Function

和 thenApply 一样,不过要求返回结果的类型是一个新的阶段,而不是由工具帮忙包装成一个阶段

Function>

根据两个独立阶段的执行结果做不同的操作

thenCombine,BiFunction

当两个独立阶段都正常执行结束时,接收这两个阶段的结果,作为入参接着执行该阶段,该阶段有返回值

BiFunction

thenAcceptBoth,BiConsumer

和 thenCombine 一样,只是没有返回值

BiConsumer

applyToEither,Function

以两个独立阶段中先正常执行结束的那个阶段的结果作为入参接着执行该阶段,有返回值

Function

acceptEither,Consumer

和 applyToEither 一样,只是没有返回值

Consumer

runAfterEither,Runnable

两个独立阶段任何一个正常执行结束,接着执行该阶段,不接收其结果或异常,也不返回结果

Runnable

runAfterBoth, Runnable

两个独立阶段都正常执行结束,才接着执行该阶段,不接收其结果或异常,也不返回结果

Runnable

演示

package jdk.java.util.concurrent;

import com.mrathena.toolkit.ThreadKit;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class CompletableFutureTest {

	private static final ExecutorService executor = Executors.newFixedThreadPool(10);
	private static final String SUCCESS = "success";

	@Test
	public void runAfterBoth() throws Throwable {
		Random random = new Random();
		CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "1";
		});
		CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "2";
		});

		CompletableFuture<Void> future = firstFuture.runAfterBoth(secondFuture, () -> log.info("finish"));

		ThreadKit.sleepSecond(3);
	}

	@Test
	public void runAfterEither() throws Throwable {
		Random random = new Random();
		CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "1";
		});
		CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "2";
		});

		CompletableFuture<Void> future = firstFuture.runAfterEither(secondFuture, () -> log.info("finish"));

		ThreadKit.sleepSecond(3);
	}

	@Test
	public void acceptEither() throws Throwable {
		Random random = new Random();
		CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "1";
		});
		CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "2";
		});

		CompletableFuture<Void> future = firstFuture.acceptEither(secondFuture, System.out::println);

		ThreadKit.sleepSecond(3);
	}

	@Test
	public void applyToEither() throws Throwable {
		Random random = new Random();
		CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "1";
		});
		CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
			int seconds = random.nextInt(3);
			log.info("{}", seconds);
			ThreadKit.sleepSecond(seconds);
			return "2";
		});

		CompletableFuture<String> future = firstFuture.applyToEither(secondFuture, fastFutureResult -> fastFutureResult);
		log.info(future.get());
	}

	@Test
	public void thenAcceptBoth() throws Throwable {
		CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return "the result of first stage";
		});

		ThreadKit.sleepSecond(2);
		System.out.println();

		CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return "the result of first stage";
		});

		CompletableFuture<Void> future = firstFuture.thenAcceptBoth(secondFuture,
				(firstStageResult, secondStageResult) -> {System.out.println(firstStageResult + " + " + secondStageResult);});

		ThreadKit.sleepSecond(2);
	}

	@Test
	public void thenCompose() throws Throwable {
		CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return "the result of first stage";
		}).thenCompose(lastStageResult -> CompletableFuture.supplyAsync(() -> {
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
			return "the result of first stage";
		}));

		log.info(future.get());
	}

	@Test
	public void thenCombine() throws Throwable {
		CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return "the result of first stage";
		});

		ThreadKit.sleepSecond(2);
		System.out.println();

		CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
			return "the result of first stage";
		});

		CompletableFuture<String> future = firstFuture.thenCombine(secondFuture,
				(firstStageResult, secondStageResult) -> firstStageResult + " + " + secondStageResult);
		log.info(future.get());
	}

	@Test
	public void thenRun() throws Throwable {
		CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return "the result of first stage";
		}).thenRun(() -> {
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
		});

		ThreadKit.sleepSecond(3);
		System.out.println();

		CompletableFuture<Void> throwableFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			int a = 10 / 0;
			log.info("first stage finish");
			return "the result of first stage";
		}).thenRun(() -> {
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
		});

		ThreadKit.sleepSecond(3);
	}

	@Test
	public void thenAccept() throws Throwable {
		CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return "the result of first stage";
		}).thenAccept(lastStageResult -> {
			log.info(lastStageResult);
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
		});

		ThreadKit.sleepSecond(3);
		System.out.println();

		CompletableFuture<Void> throwableFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			int a = 10 / 0;
			log.info("first stage finish");
			return "the result of first stage";
		}).thenAccept(lastStageResult -> {
			log.info(lastStageResult);
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
		});

		ThreadKit.sleepSecond(3);
	}

	@Test
	public void handle() throws Throwable {
		CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return SUCCESS;
		}).handle((lastStageResult, lastStageCause) -> {
			log.info("{}, {}", lastStageResult, null == lastStageCause ? null : lastStageCause.getMessage());
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
			return "the result of second stage";
		});
		log.info(future.get());

		System.out.println();

		CompletableFuture<String> throwableFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			int a = 10 / 0;
			log.info("first stage finish");
			return SUCCESS;
		}).handle((lastStageResult, lastStageCause) -> {
			log.info("{}, {}", lastStageResult, lastStageCause.getMessage());
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
			return "the result of second stage";
		});
		try {
			log.info(throwableFuture.get());
		} catch (Throwable cause) {
			log.info(cause.getMessage());
		}
	}

	@Test
	public void thenApply() throws Throwable {
		CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return "the result of first stage";
		}).thenApply(lastStageResult -> {
			log.info(lastStageResult);
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
			return "the result of second stage";
		});
		log.info(future.get());

		System.out.println();

		CompletableFuture<String> throwableFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			int a = 10 / 0;
			log.info("first stage finish");
			return "the result of first stage";
		}).thenApply(lastStageResult -> {
			log.info(lastStageResult);
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
			return "the result of second stage";
		});
		// 一个阶段出错的话, 该阶段剩下的代码不再执行, 后续的阶段也不再执行, 在get的时候会报错
		try {
			log.info(throwableFuture.get());
		} catch (Throwable cause) {
			log.info(cause.getMessage());
		}
	}

	@Test
	public void whenComplete() throws Throwable {
		CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			log.info("first stage finish");
			return SUCCESS;
		}).whenComplete((lastStageResult, lastStageCause) -> {
			log.info("{}, {}", lastStageResult, null == lastStageCause ? null : lastStageCause.getMessage());
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
		});
		// whenComplete没有提供返回值, 这里取到的是整个流程的所有阶段中, 最后一个有返回值的阶段返回的值
		log.info(future.get());

		System.out.println();

		CompletableFuture<String> throwableFuture = CompletableFuture.supplyAsync(() -> {
			log.info("first stage start");
			ThreadKit.sleepSecond(1);
			int a = 10 / 0;
			log.info("first stage finish");
			return SUCCESS;
		}).whenComplete((lastStageResult, lastStageCause) -> {
			log.info("{}, {}", lastStageResult, lastStageCause.getMessage());
			log.info("second stage start");
			ThreadKit.sleepSecond(1);
			log.info("second stage finish");
		});
		// 一个阶段出错的话, 该阶段剩下的代码不再执行, 但后续的阶段可以继续执行, 在get的时候会报错
		try {
			log.info(throwableFuture.get());
		} catch (Throwable cause) {
			log.info(cause.getMessage());
		}
	}

	@Test
	public void init() throws Throwable {

		CompletableFuture<Void> runAsyncFuture = CompletableFuture.runAsync(() -> {
			log.info("start");
			ThreadKit.sleepSecond(1);
			log.info("finish");
		});
		log.info("{}", runAsyncFuture.get());

		System.out.println();

		CompletableFuture<Void> runAsyncFutureWithExecutor = CompletableFuture.runAsync(() -> {
			log.info("start");
			ThreadKit.sleepSecond(1);
			log.info("finish");
		}, executor);
		log.info("{}", runAsyncFutureWithExecutor.get());

		System.out.println();

		CompletableFuture<String> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
			log.info("start");
			ThreadKit.sleepSecond(1);
			log.info("finish");
			return SUCCESS;
		});
		log.info("{}", supplyAsyncFuture.get());

		System.out.println();

		CompletableFuture<String> supplyAsyncFutureWithExecutor = CompletableFuture.supplyAsync(() -> {
			log.info("start");
			ThreadKit.sleepSecond(1);
			log.info("finish");
			return SUCCESS;
		}, executor);
		log.info("{}", supplyAsyncFutureWithExecutor.get());

		executor.shutdown();

	}

}

你可能感兴趣的:(java)