七、Future异步任务
Future 接口表示异步任务,是还没有完成的任务给出的未来结果。
1、FutureTask
- **作为线程:**实现了Runnable接口
- **异步处理:**实现了Future接口
- **有返回值:**构造器注入Callable
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lLGl4D40-1657286310362)(…/…/AppData/Roaming/Typora/typora-user-images/image-20220705210227435.png)]
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new MyThread());
Thread t1 = new Thread(futureTask,"t1");
t1.start();
System.out.println(futureTask.get());//接收返回值
}
}
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("-----come in call() ----异步执行");
return "hello Callable 返回值";
}
}
//结果
//-----come in call() ----异步执行
//hello Callable 返回值
**优点:**future+线程池异步多线程任务配合,能显著提高程序的执行效率。
**缺点:**一旦调用get()方法,不管是否计算完成,都会导致阻塞(所以一般get方法放到最后)
- 解决:isDone()轮询! —> 耗费CPU资源
2、CompletableFuture
1、创建异步线程:
1.1 runAsync**(无返回值)**
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(3);//加入线程池
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
//停顿几秒线程
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
},executorService); //加入线程池(若未传入,则使用默认线程池ForkJoinPool)
System.out.println(voidCompletableFuture.get());
}
}
//pool-1-thread-1 ----指定的线程池
//null ----没有返回值
1.2supplyAsync(有返回值)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(3);//加入线程池
CompletableFuture<String> objectCompletableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "helllo supplyasync";
},executorService);
System.out.println(objectCompletableFuture.get());
}
}
//ForkJoinPool.commonPool-worker-9---------默认的线程池
//helllo supplyasync-------------supplyasync有返回值了
2、使用CompletableFuture处理异步任务
public class CompletableFutureUseDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Object> objectCompletableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"----副线程come in");
int result = ThreadLocalRandom.current().nextInt(10);//产生一个随机数
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1秒钟后出结果"+result);
return result;
});
System.out.println(Thread.currentThread().getName()+"线程先去忙其他任务");
System.out.println(objectCompletableFuture.get());
}
}
//main线程先去忙其他任务(异步)
//ForkJoinPool.commonPool-worker-9----副线程come in
//1秒钟后出结果6
//6
CompletableFuture优点总结
- 异步任务结束时,会自动回调某个对象的方法;
- 主线程设置好回调后,不再关心异步任务的执行,异步任务之间可以顺序执行
- 异步任务出错时,会自动回调某个对象的方法。
1、CompletableFuture获取结果API:
- public T get() 不见不散,容易阻塞
- public T get(long timeout,TimeUnit unit) 过时不候,超过时间会爆异常
- public T join() 类似于get(),区别在于是否需要抛出异常
- public T getNow(T valueIfAbsent)
2、对计算结果进行处理
thenApply
计算结果存在在依赖关系,使得线程串行化。因为依赖关系,所以一旦有异常,直接叫停。(常用!!!)handle
类似于thenApply,但是有异常的话仍然可以往下走一步。
public class CompletableFutureDemo2
{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
//当一个线程依赖另一个线程时用 thenApply 方法来把这两个线程串行化,
//加入线程池(若未传入,则使用默认线程池ForkJoinPool)
CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("111");
return 1024;
}).thenApply(f -> {
System.out.println("222");
return f + 1;
}).thenApply(f -> {
//int age = 10/0; // 异常情况:那步出错就停在那步。
System.out.println("333");
return f + 1;
}).whenCompleteAsync((v,e) -> {
System.out.println("*****v: "+v);
}).exceptionally(e -> {
e.printStackTrace();
return null;
});
System.out.println("-----主线程结束,END");
// 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
//-----正常情况
//111
//222
//333
//----计算结果: 6
//-----异常情况
//111
//异常.....