Guava 的异步回调
Guava是谷歌公司提供的 Java 扩展包,提供了一种异步回调的解决方案。
Guava 对 Java 的异步回调机制,做了以下的增强:
(1)引入了一个新的接口 ListenableFuture,继承了 Java 的 Future 接口,使得 Java 的 Future异步任务,在 Guava 中能被监控和获得非阻塞异步执行的结果。
(2)引入了一个新的接口 FutureCallback,这是一个独立的新接口。该接口的目的,是在异步任务执行完成后,根据异步结果,完成不同的回调处理,并且可以处理异步结果。
Guava 异步回调的流程如下:
第 1 步:实现 Java 的 Callable 接口,创建异步执行逻辑。还有一种情况,如果不需要返回值,异步执行逻辑也可以实现 Java 的 Runnable 接口。
第 2 步:创建 Guava 线程池。
第 3 步:将第 1 步创建的 Callable/Runnable 异步执行逻辑的实例,通过 submit 提交到 Guava线程池,从而获取 ListenableFuture 异步任务实例。
第 4 步:创建 FutureCallback 回调实例,通过 Futures.addCallback 将回调实例绑定到ListenableFuture 异步任务上。
完成以上四步,当 Callable/Runnable 异步执行逻辑完成后,就会回调异步回调实例FutureCallback 的回调方法onSuccess/onFailure
使用 Guava 实现泡茶喝的实践案例
代码实现:
public class GuavaFutureDemo {
public static final int SLEEP_GAP = 500;
public static String getCurThreadName() {
return Thread.currentThread().getName();
}
static class HotWater implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
try {
System.out.println("洗好水壶");
System.out.println("灌上凉水");
System.out.println("放在火上");
//睡一段时间 代表烧水
Thread.sleep(SLEEP_GAP);
System.out.println("水烧好了。");
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("烧水 线程发生异常中断");
return false;
}
System.out.println("烧水 线程完成");
return true;
}
}
static class Wash implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
try {
System.out.println("洗茶杯");
System.out.println("洗水壶");
//睡一段时间 洗水壶
Thread.sleep(SLEEP_GAP);
System.out.println("洗完了。");
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("清洗 线程完成");
return false;
}
System.out.println("清洗 线程结束");
return true;
}
}
static class MainJob implements Runnable {
Boolean hOK = false;
Boolean wOK = false;
@Override
public void run() {
while (true) {
try {
Thread.sleep(SLEEP_GAP);
System.out.println("等待中 看会儿书~~~");
} catch (InterruptedException e) {
e.printStackTrace();
}
if (hOK && wOK) System.out.println("可以泡茶了,泡茶喝");
}
}
}
public static void main(String[] args) {
//创建一个新的线程实例,作为泡茶主线程
MainJob mainJob = new MainJob();
Thread mainThread = new Thread(mainJob);
mainThread.setName("主线程");
mainThread.start();
//烧水和清洗的实例
Callable<Boolean> hotCallable = new HotWater();
Callable<Boolean> wCallable = new Wash();
//创建 Java 线程池
ExecutorService jpool = Executors.newFixedThreadPool(10);
//包装 Java 线程池,构造 Guava 线程池
ListeningExecutorService gpool = MoreExecutors.listeningDecorator(jpool);
//提交烧水的业务逻辑实例,到 Guava 线程池获取异步任务
ListenableFuture<Boolean> hFuture = gpool.submit(hotCallable);
//绑定异步回调,烧水完成后,把喝水任务的 warterOk 标志设置为 true
Futures.addCallback(hFuture, new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean aBoolean) {
if (aBoolean) mainJob.hOK = true;
}
@Override
public void onFailure(Throwable throwable) {
System.out.println("烧水失败 !");
}
});
//提交清洗的业务逻辑实例,到 Guava 线程池获取异步任务
ListenableFuture<Boolean> wFuture = gpool.submit(wCallable);
//绑定任务执行完成后的回调逻辑到异步任务
Futures.addCallback(wFuture, new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean aBoolean) {
if (aBoolean) mainJob.wOK = true;
}
@Override
public void onFailure(Throwable throwable) {
System.out.println("清洗失败 !");
}
});
}
}
Guava 异步回调和 Java 的 FutureTask 异步回调,本质的不同在于:
- Guava 是非阻塞的异步回调,调用线程是不阻塞的,可以继续执行自己的业务逻辑。
- FutureTask 是阻塞的异步回调,调用线程是阻塞的,在获取异步结果的过程中,一直阻塞,等待异步线程返回结果。