• java中Future的使用



    java中Future的使用

    Future是java 1.5引入的一个interface,可以方便的用于异步结果的获取。 本文将会通过具体的例子讲解如何使用Future。

    创建Future

    正如上面所说,Future代表的是异步执行的结果,意思是当异步执行结束之后,返回的结果将会保存在Future中。

    那么我们什么时候会用到Future呢? 一般来说,当我们执行一个长时间运行的任务时,使用Future就可以让我们暂时去处理其他的任务,等长任务执行完毕再返回其结果。

    经常会使用到Future的场景有:1. 计算密集场景。2. 处理大数据量。3. 远程方法调用等。

    接下来我们将会使用ExecutorService来创建一个Future。

        <T> Future<T> submit(Callable<T> task);
    

    上面是ExecutorService中定义的一个submit方法,它接收一个Callable参数,并返回一个Future。

    我们用一个线程来计算一个平方运算:

        private ExecutorService executor
                = Executors.newSingleThreadExecutor();
    
        public Future<Integer> calculate(Integer input) {
            return executor.submit(() -> {
                System.out.println("Calculating..."+ input);
                Thread.sleep(1000);
                return input * input;
            });
        }
    

    submit需要接受一个Callable参数,Callable需要实现一个call方法,并返回结果。这里我们使用lamaba表达式来简化这一个流程。

    从Future获取结果

    上面我们创建好了Future,接下来我们看一下怎么获取到Future的值。

           FutureUsage futureUsage=new FutureUsage();
            Future<Integer> futureOne = futureUsage.calculate(20);
            while(!futureOne.isDone()) {
                System.out.println("Calculating...");
                Thread.sleep(300);
            }
            Integer result = futureOne.get();
    

    首先我们通过Future.isDone() 来判断这个异步操作是否执行完毕,如果完毕我们就可以直接调用futureOne.get()来获得Futre的结果。

    这里futureOne.get()是一个阻塞操作,会一直等待异步执行完毕才返回结果。

    如果我们不想等待,future提供了一个带时间的方法:

    Integer result = futureOne.get(500, TimeUnit.MILLISECONDS);
    

    如果在等待时间结束的时候,Future还有返回,则会抛出一个TimeoutException。

    取消Future

    如果我们提交了一个异步程序,但是想取消它, 则可以这样:

    uture<Integer> futureTwo = futureUsage.calculate(4);
    
            boolean canceled = futureTwo.cancel(true);
    

    Future.cancel(boolean) 传入一个boolean参数,来选择是否中断正在运行的task。

    如果我们cancel之后,再次调用get()方法,则会抛出CancellationException。

    多线程环境中运行

    如果有两个计算任务,先看下在单线程下运行的结果。

            Future<Integer> future1 = futureUsage.calculate(10);
            Future<Integer> future2 = futureUsage.calculate(100);
    
            while (!(future1.isDone() && future2.isDone())) {
                System.out.println(
                        String.format(
                                "future1 is %s and future2 is %s",
                                future1.isDone() ? "done" : "not done",
                                future2.isDone() ? "done" : "not done"
                        )
                );
                Thread.sleep(300);
            }
    
            Integer result1 = future1.get();
            Integer result2 = future2.get();
    
            System.out.println(result1 + " and " + result2);
    

    因为我们通过Executors.newSingleThreadExecutor()来创建的单线程池。所以运行结果如下:

    Calculating...10
    future1 is not done and future2 is not done
    future1 is not done and future2 is not done
    future1 is not done and future2 is not done
    future1 is not done and future2 is not done
    Calculating...100
    future1 is done and future2 is not done
    future1 is done and future2 is not done
    future1 is done and future2 is not done
    100 and 10000
    

    如果我们使用Executors.newFixedThreadPool(2)来创建一个多线程池,则可以得到如下的结果:

    calculating...10
    calculating...100
    future1 is not done and future2 is not done
    future1 is not done and future2 is not done
    future1 is not done and future2 is not done
    future1 is not done and future2 is not done
    100 and 10000
    

    本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/future

    更多教程请参考 flydean的博客

  • 相关阅读:
    软件测试——C#判断密码是否符合要求
    软件测试——C#判断闰年的form小程序
    初识JUnit
    软件测试的方法一共有几种
    多个异步请求调用一个回调函数
    单元测试、集成测试、系统测试总结
    软件测试同行评审流程
    白盒测试总结
    黑盒测试总结
    闰年测试
  • 原文地址:https://www.cnblogs.com/flydean/p/12680281.html
Copyright © 2020-2023  润新知