Java的异步编程(一):Future的使用

一:Future介绍和使用

  1. 简介:Future、Callback和Promise模式是在并发编程中常常会用到的非阻塞的模型;
    a)其中Future模式能够理解为将任务提交给线程执行,其执行结果为Future(将来的结果),期间能够去作其余事情,等须要结果时,再从Future那里获取结果;其中Future模式能够理解为将任务提交给线程执行,其执行结果为Future(将来的结果),期间能够去作其余事情,等须要结果时,再从Future那里获取结果;
    b)Java中还未实现带Callback的Future模式,但在Netty、Guava、Vert.x等扩展工具包中已实现,Promise模式是解决一些Callback带来的问题引入的;
  2. Future的使用
    Future通常搭配Callable来使用,通常咱们使用Thread或者ExecutorService来执行,并返回执行结果Future;
    Example:以下所示,在下例中启动2个线程,分别执行耗时2s的任务,最终耗时为2067ms,这就起到异步执行的效果,
private void futureInvokeResult() {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        long mills = System.currentTimeMillis();
        Callable<String> callable = () -> { Thread.sleep(2000);return "123"; };
        Future<String> future1 = executor.submit(callable);
        Future<String> future2 = executor.submit(callable);
        Future<String> future3 = executor.submit(callable);
        /**没有刻意抛出异常的状况*/
        try {
            System.out.println("Answer :" + future1.get(4, TimeUnit.SECONDS) +
                    future2.get(4, TimeUnit.SECONDS) + future3.get(4, TimeUnit.SECONDS));
        } catch (Exception e) {
            System.out.println(e);
        }
        System.out.println("总耗时:" + (System.currentTimeMillis() - mills));
        executor.shutdown();
    }

运行结果java

Answer :123123123
总耗时:2067web

  1. 异常控制:
    上面举得例子是没有刻意抛出异常的场景,下面举出能够抛出异常的场景,这时能够捕获其异常
private void futureInvokeResult() {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        long mills = System.currentTimeMillis();
        Callable<String> callable = () -> { Thread.sleep(2000);return "123"; };
        Callable<String> callable2 = () -> { throwException();return "123"; };
        Future<String> future1 = executor.submit(callable);
        Future<String> future2 = executor.submit(callable2);
        Future<String> future3 = executor.submit(callable);

        /**刻意抛出异常的状况*/
        try {
            System.out.println("Answer :" + future1.get(4, TimeUnit.SECONDS) +
                    future2.get(4, TimeUnit.SECONDS) + future3.get(4, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            System.out.println(e);
        }catch (ExecutionException e) {
            System.out.println(e);
        }catch (TimeoutException e) {
            System.out.println(e);
        }catch (Exception e) {
            System.out.println(e);
        }

        System.out.println("总耗时:" + (System.currentTimeMillis() - mills));
        executor.shutdown();
    }
    private void throwException() throws TimeoutException{
        throw new RuntimeException("111");
    }

java.util.concurrent.ExecutionException: java.lang.RuntimeException: 111
总耗时:2057编程

  1. Future接口的方法介绍
public interface Future<V> {
    //试图去cancel线程的执行,mayInterruptIfRunning为true时,能够cancel执行中的线程,
    //如果线程已经执行完、、已经取消或不能取消,则返回false,未开始、不能执行返回true;
    boolean cancel(boolean mayInterruptIfRunning);
   //在它完成前,是否已经取消
    boolean isCancelled();
   //正常结束、异常终止或取消,返回true
    boolean isDone();
   //尝试去获取结果,并等待执行完成
    V get() throws InterruptedException, ExecutionException;
 //尝试去获取结果,并等待执行完成,超时则异常
    V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
}

二:Future的缺点和改进并发

  1. 缺点:
    a)Future.get必需要阻塞的进行结果获取,或者是使用isDone()轮询进行结果查询;
    b)Future功能比较单一,仅仅提供了针对一个线程操做的,没有提供一系列方便的操做,好比上面例子中还须要单点的去执行,不能针对List去执行;
  2. Java8中引入了CompletableFuture,提供了一系列的优化;