Future的用法
多线程场景时,一般是实现runnable接口,覆写run方法,返回值是void类型,因此这种情况下不需要线程的返回结果。
如果需要线程的返回结果,就需要用callable接口来代替了。
callable用法和runnable一样,只不过覆写的是call方法,该方法有一个泛型返回值类型,可以根据需要指定。
那么何时到Future呢?当你启动callable线程时,就可以声明一个Future对象,用于接收返回结果。
Futrue可以监视目标线程调用call的情况,当你调用Future的get()方法以获得结果时,调用方的线程就被阻塞,直到目标线程的call方法结束并返回结果。
Future接口,一般都是取回Callable执行的状态用的。其中的主要方法:
cancel,取消Callable的执行,当Callable还没有完成时
get,获得Callable的返回值
isCanceled,判断是否取消了
isDone,判断是否完成
举个栗子。
四个刚需(线程)去买房摇号,future获取摇号结果。摇号结果未出,就一直阻塞。
public class FutureTest {
/**
* 买房摇号
*/
public static class Yaohao implements Callable<Integer> {
/**
* 返回摇号结果
* @return 0:中签 1:没中
* @throws Exception
*/
@Override
public Integer call() throws Exception {
Random random = new Random();
//模拟摇号,10天内出结果
TimeUnit.SECONDS.sleep(random.nextInt(10));
int result = random.nextInt(2);
System.out.println(" "+Thread.currentThread().getName()+" is done!");
return result;
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Yaohao gangxu1 = new Yaohao();
Yaohao gangxu2 = new Yaohao();
ExecutorService es = Executors.newCachedThreadPool();
Future<Integer> result1 = es.submit(gangxu1);
Future<Integer> result2 = es.submit(gangxu2);
es.shutdown();
System.out.println("刚需1,摇号结果:"+(result1.get()==1?"中签":"没中"));
System.out.println("刚需2,摇号结果:"+(result2.get()==1?"中签":"没中"));
}
}
CompletableFuture的用法
创建异步操作,runAsync(不支持返回值) 和 supplyAsync方法(支持返回值)
计算结果完成时的回调方法
whenComplete:执行完当前任务的线程,继续执行 whenComplete 的任务。
whenCompleteAsync: 执行完当前任务的线程,把whenCompleteAsync 的任务继续提交给线程池来执行。
exceptionally:当前任务出现异常时,执行exceptionally中的回调方法。
thenApply 方法,当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。
handle 方法
handle 是执行任务完成时对结果的处理。
handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。
thenAccept 消费处理结果,接收任务的处理结果,并消费处理,无返回结果。
thenRun 方法,跟 thenAccept 方法不一样的是,不关心任务的处理结果。只要上面的任务执行完成,就开始执行 thenAccept 。
thenCombine 合并任务,thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。
thenCompose 方法,thenCompose 方法允许你对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作。
案例:
1、 runAsync 和 supplyAsync方法
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可以支持返回值。
示例
//无返回值
public static void runAsync() throws Exception {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
System.out.println("run end ...");
});
future.get();
}
//有返回值
public static void supplyAsync() throws Exception {
CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
System.out.println("run end ...");
return System.currentTimeMillis();
});
long time = future.get();
Syst