[JUC-13] 异步回调

1、Future接口

  Future 接口在 Java 5 中被引入,设计初衷是对将来某个时刻会发生的结果进行建模。它建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被返回给调用方。在Future中触发那些潜在耗时的操作把调用线程解放出来,让它能继续执行其他有价值的工作,不需要等待耗时的操作完成。

  示例:使用Future以异步的方式执行一个耗时的操作:

ExecutorService executor = Executors.newCachedThreadPool();
Future<Double> future = executor.submit(new Callable<Double>() {
    
     //向ExecutorService提交一个Callable对象 
	public Double call() {
    
    
		return doSomeLongComputation();//以异步方式在新线程中执行耗时的操作
  }
});
doSomethingElse();
try {
    
    
	Double result = future.get(1, TimeUnit.SECONDS);//获取异步操作结果,如果被阻塞,无法得到结果,在等待1秒钟后退出
} catch (ExecutionException ee) {
    
    
	// 计算抛出一个异常
} catch (InterruptedException ie) {
    
    
	// 当前线程在等待过程中被中断
} catch (TimeoutException te) {
    
    
	// 在Future对象完成之前超时
}

  这种编程方式让你的线程可以在ExecutorService以并发方式调用另一个线程执行耗时操作的同时,去执行一些其他任务。如果已经运行到没有异步操作的结果就无法继续进行时,可以调用它的get方法去获取操作结果。如果操作已经完成,该方法会立刻返回操作结果,否则它会阻塞线程,直到操作完成,返回相应的结果。

  为了处理长时间运行的操作永远不返回的可能性,虽然Future提供了一个无需任何参数的get方法,但还是推荐使用重载版本的get方法,它接受一个超时的参数,可以定义线程等待Future结果的时间,而不是永无止境地等待下去。
在这里插入图片描述

  Future接口的局限性:Future接口提供了方法来检测异步计算是否已经结束(使用isDone方法),等待异步操作结束,以及获取计算的结果。但这些特性还不足以让你编写简洁的并发代码。

  1、将两个异步计算合并为一个,这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果。
  2、等待Future集合中的所有任务都完成。
  3、仅等待Future集合中快结束的任务完成,并返回它的结果。
  4、通过编程方式完成一个Future任务的执行。
  5、应对Future的完成事件(即当Future的完成事件发生时会收到通知,并能使用Future计算的结果进行下一步操作,不只是简单地阻塞等待操作结果)。

2、CompletableFuture

  CompletableFuture类提供了大量精巧的工厂方法,使用这些方法能更容易地完成整个流程,不用担心实现细节。

2.1 无返回值的 runAsync 异步回调

public class CompletableFutureTest {
    
    
    public static void main(String[] args) throws Exception {
    
    
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
    
    
            try {
    
    
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "runAsync=>Void");
        });

        System.out.println("1111");
        completableFuture.get();
    }
}

2.2 有返回值的 supplyAsync 异步回调

public class CompletableFutureTest {
    
    
    public static void main(String[] args) throws Exception {
    
    
        CompletableFuture<Integer> completableFuture =
                CompletableFuture.supplyAsync(() -> {
    
    
                    System.out.println(Thread.currentThread().getName() + "supplyAsync=>Integer");
                    int i = 10 / 0;
                    return 1024;
                });
        System.out.println(completableFuture.whenComplete((t, u) -> {
    
    
            System.out.println("t=>" + t); // 正常的返回结果
            System.out.println("u=>" + u); // 错误信息:java.util.concurrent.CompletionException:java.lang.ArithmeticException: /byzero
        }).exceptionally((e) -> {
    
    
            System.out.println(e.getMessage());
            return 233; // 可以获取到错误的返回结果
        }).get());
    }
}

猜你喜欢

转载自blog.csdn.net/qq_29051413/article/details/108002189