CompletableFuture中的四个核心静态方法用来获取CompletableFuture对象
- runAsync 方法无返回值
runAsync(Runnable runnable)
runAsync(Runnable runnable, Executor executor)
- supplyAsync 方法有返回值
supplyAsync(Supplier<U> supplier)
supplyAsync(Supplier<U> supplier,Executor executor)
其中第二个参数为线程池对象,如果不提供线程池,会采用默认的线程池
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "hello supplyAsync";
});
System.out.println(completableFuture.get());
// 此时输出结果为
// ForkJoinPool.commonPool-worker-1
// hello supplyAsync
提供了线程池对象后
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return "hello supplyAsync";
}, threadPool);
System.out.println(completableFuture.get());
threadPool.shutdown();
// 此时输出结果为
// pool-1-thread-1
// hello supplyAsync
通用异步编程
依旧是上面的程序,不过这次多了几个步骤
whenComplete方法从以下代码可以看出,接口中需要两个参数,一个是上个方法调用后的返回值,另一个则是错误信息
whenComplete(BiConsumer<? super T, ? super Throwable> action)
exceptionally方法里面的需要传入一个函数,并且函数的类型正好是异常类
exceptionally(Function<Throwable, ? extends T> fn)
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "正在运行");
// 获得一个 10 以内随机的数字
int result = ThreadLocalRandom.current().nextInt(10);
try {
// 模拟程序的执行过程
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("输出结果为" + result);
return result;
// value 表示上一个方法的返回值,error 表示异常
}).whenComplete((value, error) -> {
if (error == null) {
System.out.println("计算完成,结果耗时:" + value);
}
// 这里的 error 就是异常
}).exceptionally(error -> {
error.printStackTrace();
System.out.println("异常情况:" + error.getCause() + "\t" + error.getMessage());
return null;
});
System.out.println("main线程正在运行...");
// 输出结果为
// ForkJoinPool.commonPool-worker-1正在运行
// main线程正在运行...
上面代码执行时,whenComplete并没有执行,因为使用默认的线程池如同守护线程一般,主线程结束后就会自动关闭。可以使用功能自定义的的线程池解决这个问题
// 创建线程池对象
ExecutorService threadPool = Executors.newFixedThreadPool(3);
try {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "正在运行");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("输出结果为" + result);
return result;
}, threadPool).whenComplete((value, error) -> {
if (error == null) {
System.out.println("计算完成,结果耗时:" + value);
}
}).exceptionally(error -> {
error.printStackTrace();
System.out.println("异常情况:" + error.getCause() + "\t" + error.getMessage());
return null;
});
System.out.println("main线程正在运行...");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭线程池
threadPool.shutdown();
}
// 输出结果为
// pool-1-thread-1正在运行
// main线程正在运行...
// 输出结果为2
// 计算完成,结果耗时:2
CompletableFuture中的常用方法
获取结果
- get 和 join 都可以获取返回值,但 get 方法使用时需要捕捉异常,而 join 方法不需要
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "线程执行了");
return true;
});
try {
// 输出结果
// ForkJoinPool.commonPool-worker-1 线程执行了
// true
System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
// 输出结果
// ForkJoinPool.commonPool-worker-1 线程执行了
// true
System.out.println(Thread.currentThread().getName() + "\t" + "线程执行了");
return true;
});
System.out.println(future.join());
-
有参数的 get 后面跟时间,表示等待的时间,超过后会抛出异常
get(long timeout, TimeUnit unit)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello,World!";
});
try {
// 当时间为 1 秒时会抛出 TimeOut 异常
// future.get(1, TimeUnit.SECONDS);
System.out.println(future.get(3, TimeUnit.SECONDS));
// 当设置为 3 秒时,正常输出 Hello,World!
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
}
- getNow 方法在没有计算完成时会返回传入的值,计算完成后会返回计算之后的结果值
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello,World!";
});
System.out.println(future.getNow("Not Value"));
// 输出 Not Value
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(future.getNow("Not Value"));
// 输出 Hello,World!
- complete 方法返回 bool ,表示是否打断了当前线程任务,并返回结果
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello,World!";
});
// System.out.println(future.complete("Not Value"));
// System.out.println(future.join());
// true
// Not Value
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(future.complete("Not Value"));
System.out.println(future.join());
// false
// Hello,World!
对计算结果进行处理
- thenApply 计算结果存在依赖关系,两个线程串行化,出异常会中断
CompletableFuture.supplyAsync(() -> {
System.out.println("第一步");
return 10;
}).thenApply((f) -> {
// 模拟异常
int i = 10 / 0;
System.out.println("第二步");
return f + 10;
}).thenApply((f) -> {
System.out.println("第三步");
return f + 10;
}).whenComplete((val, err) -> {
System.out.println("第四步");
System.out.println(val);
}).exceptionally((err) -> {
err.printStackTrace();
System.out.println(err.getMessage());
return null;
});
// 未出异常的结果 出现异常结果
// 第一步 第一步
// 第二步 第四步
// 第三步 null
// 第四步
// 30
- handle 出现异常不会中断
CompletableFuture.supplyAsync(() -> {
System.out.println("第一步");
return 10;
}).handle((f, e) -> {
// 模拟异常
int i = 10 / 0;
System.out.println("第二步");
return f + 10;
}).handle((f, e) -> {
System.out.println("第三步");
return f + 10;
}).whenComplete((val, err) -> {
System.out.println("第四步");
System.out.println(val);
}).exceptionally((err) -> {
err.printStackTrace();
System.out.println(err.getMessage());
return null;
});
// 未出异常的结果 出现异常结果
// 第一步 第一步
// 第二步 第三步
// 第三步 第四步
// 第四步 null
// 30
对计算结果进行消费
- thenAccept 对结果进行消费
CompletableFuture.supplyAsync(() -> 1).
thenApply((f) -> f + 1).
thenAccept(System.out::println);
// 输出结果为 2
线程池运行选择
使用了自定义的线程池后,使用 thenRun 都是使用的同一个线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行了");
return -1;
}, threadPool).thenRun(() -> System.out.println(Thread.currentThread().getName() + "执行了")
).thenRun(() -> System.out.println(Thread.currentThread().getName() + "执行了"));
threadPool.shutdown();
// 输出结果
// pool-1-thread-1执行了
// pool-1-thread-1执行了
// pool-1-thread-1执行了
当使用 thenRunAsync 后,后面的线程不一定就是原来的线程池对象了
ExecutorService threadPool = Executors.newFixedThreadPool(5);
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行了");
return -1;
}, threadPool).thenRunAsync(() -> System.out.println(Thread.currentThread().getName() + "执行了")
).thenRun(() -> System.out.println(Thread.currentThread().getName() + "执行了"));
threadPool.shutdown();
// 输出结果
// pool-1-thread-1执行了
// ForkJoinPool.commonPool-worker-1执行了
// ForkJoinPool.commonPool-worker-1执行了
对计算速度进行选用
applyToEither 方法谁快,传入的参数为运行快的线程的哪一个结果
CompletableFuture<String> gamerA = CompletableFuture.supplyAsync(() -> {
System.out.println("A come in...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "gamer A";
});
CompletableFuture<String> gamerB = CompletableFuture.supplyAsync(() -> {
System.out.println("B come in...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "gamer B";
});
CompletableFuture<String> result = gamerA.applyToEither(gamerB, (f) ->
f + " is winner"
);
System.out.println(Thread.currentThread().getName() + "\t" + result.join());
// 输出结果
// A come in...
// B come in...
// main gamer A is winner
对计算结果进行合并
thenCombine 方法有两个参数,一个是另外一个线程对象,另一个则是 BiFunction 接口,有两个参数函数接口,两个参数分别对应两个线程对象的结果
CompletableFuture<Integer> thenCombine = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in 1");
return 10;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in 2");
return 20;
}), (x, y) -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in 3");
return x + y;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in 4");
return 30;
}), (x, y) -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in 5");
return x + y;
});
System.out.println(Thread.currentThread().getName() + "\t" + thenCombine.join());
// 输出结果
// ForkJoinPool.commonPool-worker-1 ---come in 1
// ForkJoinPool.commonPool-worker-2 ---come in 2
// ForkJoinPool.commonPool-worker-3 ---come in 4
// ForkJoinPool.commonPool-worker-2 ---come in 3
// ForkJoinPool.commonPool-worker-2 ---come in 5
// main 60