Future 执行异步任务
public class AnswerApp {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<Integer> future = executorService.submit(() -> {
logger("模拟异步耗时任务开始...");
try {
// 模拟耗时任务
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger("模拟异步耗时任务结束!!!");
return 10;
});
//当前线程继续做其他事情
logger("处理其他事情...\n");
// 当前主线程阻塞, 直到获取异步操作的结果
Integer result = future.get();
logger("result: " + result);
}
}
程序运行结果
2019-06-28 18:20:22:618 模拟异步耗时任务开始...
2019-06-28 18:20:22:618 处理其他事情...
2019-06-28 18:20:27:622 模拟异步耗时任务结束!!!
2019-06-28 18:20:27:622 result: 10
FutureTask 执行异步任务
public class AnswerApp {
public static void main(String[] args) throws Exception {
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
logger("异步耗时任务开始...");
// 模拟耗时任务
Thread.sleep(5000);
return 100;
});
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(futureTask);
// 阻塞, 直到获取异步任务结果
logger("result: " + futureTask.get());
executorService.shutdown();
}
}
程序运行结果
2019-06-28 18:14:46:272 异步耗时任务开始...
2019-06-28 18:14:51:274 result: 100
Future 接口可以执行异步任务,但却有其局限性。 它很难直接表述多个 Future 结果之间的依赖性。
- 将多个异步计算的结果合并成一个
- 等待 Future 集合中的所有任务都完成
- Future 任务完成以后触发执行动作
CompletableFuture 执行异步任务
public class AnswerApp {
public static void main(String[] args) throws Exception {
CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
logger("获取数据(耗时任务)开始...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger("已经拿到数据啦~~~");
return 10;
}).thenApply((data) -> {
logger(MessageFormat.format("对拿到的·数据{0}·进行加工处理...", data));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return data * data;
}).whenCompleteAsync((r, e) -> logger("最终数据: " + r));
logger("主线程正在执行耗时任务\n");
Thread.sleep(3000);
logger("主线程耗时任务执行完成\n");
completableFuture.get();
}
}
程序运行结果
2019-06-28 19:18:40:947 获取数据(耗时任务)开始...
2019-06-28 19:18:40:947 主线程正在执行耗时任务
2019-06-28 19:18:43:952 主线程耗时任务执行完成
2019-06-28 19:18:45:951 已经拿到数据啦~~~
2019-06-28 19:18:45:971 对拿到的·数据10·进行加工处理...
2019-06-28 19:18:47:972 最终数据: 100
结合两个 CompletableFuture
public class AnswerApp {
public static void main(String[] args) throws Exception {
CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
logger("数据提取数据(耗时任务)...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger("数据已经拿到啦~~~");
return 10;
}).thenCompose(preRlt -> CompletableFuture.supplyAsync(() -> {
logger("我拿到了上一步任务的数据啦~ preRlt: " + preRlt);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10 + preRlt;
}));
logger("最终结果数据: " + completableFuture.get());
}
}
程序运行结果
2019-06-28 18:31:44:491 数据提取数据(耗时任务)...
2019-06-28 18:31:49:496 数据已经拿到啦~~~
2019-06-28 18:31:49:499 我拿到了上一步任务的数据啦~ preRlt: 10
2019-06-28 18:31:54:501 最终结果数据: 20
并行执行多个异步任务
public class AnswerApp {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
logger("耗时·任务1·准备开始...");
try {
// 模拟耗时任务1
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger("我已经拿到耗时·任务1·的数据啦~~~");
return 10;
});
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
logger("耗时·任务2·准备开始...");
try {
// 模拟耗时任务2
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger("我已经拿到耗时·任务2·的数据啦~~~");
return 20;
});
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(completableFuture1, completableFuture2);
// 这个方法不会合并结果,可以看到他的返回值是 Void 类型
combinedFuture.get();
Optional<Integer> sum = Stream.of(completableFuture1, completableFuture2).map(CompletableFuture::join).reduce((x, y) -> x + y);
logger("两个任务的结果和: " + String.valueOf(sum.orElse(0)));
logger("程序总共耗时 " + (System.currentTimeMillis() - start) / 1000 + " s");
}
程序运行结果
2019-06-28 19:04:20:936 耗时·任务2·准备开始...
2019-06-28 19:04:20:936 耗时·任务1·准备开始...
2019-06-28 19:04:23:939 我已经拿到耗时·任务2·的数据啦~~~
2019-06-28 19:04:25:939 我已经拿到耗时·任务1·的数据啦~~~
2019-06-28 19:04:25:943 两个任务的结果和: 30
2019-06-28 19:04:25:943 程序总共耗时 5 s
异常处理
public class AnswerApp {
public static void main(String[] args) throws Exception {
String name = null;
// 第一个参数为 CompletableFuture 返回的结果, 第二个参数为抛出的异常
// s: CompletableFuture 返回的结果, t: 抛出的异常
CompletableFuture completableFuture1 = CompletableFuture.supplyAsync(() -> {
Assert.notNull(name, "name is null");
return MessageFormat.format("hello {0}", name);
}).handle((s, t) -> s != null ? s : t.getMessage());
logger("最终拿到的结果1: " + completableFuture1.get());
System.out.println();
String userName = "answer";
CompletableFuture completableFuture2 = CompletableFuture.supplyAsync(() -> {
Assert.notNull(userName, "userName is null");
return MessageFormat.format("hello {0}", userName);
}).handle((s, t) -> s != null ? s : t.getMessage());
logger("最终拿到的结果2: " + completableFuture2.get());
}
}
程序运行结果
2019-06-28 19:07:38:136 最终拿到的结果1: java.lang.IllegalArgumentException: name is null
2019-06-28 19:07:38:139 最终拿到的结果2: hello answer
日志打印方法
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS");
private static void logger(String log) {
System.out.println(MessageFormat.format("{0} {1}", LocalDateTime.now().format(FORMATTER), log));
}
Reference