美文网首页
Future介绍

Future介绍

作者: 张明学 | 来源:发表于2020-08-15 15:02 被阅读0次

    在并发编程中,我们经常用到非阻塞的模型,不管是继承thread类还是实现runnable接口,都无法保证获取到之前的执行结果。Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。

    Future

    Future有5个方法

    /**
     * 方法可以用来停止一个任务,如果任务可以停止(通过mayInterruptIfRunning来进行判断),则可以返回true,如果任务已经完成或者已经停止,或者这个任务无法停止,则会返回false.
     */
    boolean cancel(boolean mayInterruptIfRunning);
    
    /**
     * 方法判断当前方法是否取消
     */
    boolean isCancelled();
    
    /**
     * 方法判断当前方法是否完成
     */
    boolean isDone();
    
    /**
     * 方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线程,直到任务执行完毕
     */
    V get() throws InterruptedException, ExecutionException;
    
    /**
     * 做多等待timeout的时间就会返回结果
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
    

    原来的做法

    // 耗时5秒的复杂事务
    public static String longTimeDoSomething() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "DoSomething-Result";
    }
    
    // 耗时2秒的复杂计算
    public static Long complexCompute() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 100L;
    }
    

    不开子线程处理

    @Test
    public void test1() {
        Long startTime = System.currentTimeMillis();
        // 耗时5秒的复杂事务
        String result1 = Computer.longTimeDoSomething();
        // 耗时2秒的复杂计算
        Long result2 = Computer.complexCompute();
        Long endTime = System.currentTimeMillis();
        log.info("耗时={}毫秒,结果={},{}", (endTime - startTime), result1, result2);
    }
    

    [ main]耗时=7009毫秒,结果=DoSomething-Result,100

    开两个子线程

    @Test
    public void test2() throws Exception {
        Long startTime = System.currentTimeMillis();
    
        Object[] objects = new Object[2];
        Thread thread1 = new Thread(() -> {
            String result1 = Computer.longTimeDoSomething();
            log.info("thread1执行完毕,结果={}", result1);
            objects[0] = result1;
        });
        thread1.start();
        thread1.join();
    
        Thread thread2 = new Thread(() -> {
            Long result2 = Computer.complexCompute();
            log.info("thread2执行完毕,结果={}", result2);
            objects[1] = result2;
        });
        thread2.start();
        thread2.join();
    
        Long endTime = System.currentTimeMillis();
        log.info("耗时={}毫秒,结果={},{}", (endTime - startTime), objects[0], objects[1]);
    }
    

    [Thread-1]thread1执行完毕,结果=DoSomething-Result [Thread-2]thread2执行完毕,结果=100 [ main]耗时=7083毫秒,结果=DoSomething-Result,100

    为了得到thread1和thread2两个子线程的结果,必须得将两个子线程join(当前线程等待另一个调用join()方法的线程执行结束后再往下执行),这样可以保证主线程可以拿到子线程的结果。但是这样和同步操作也没有什么区别!

    FutureTask

    我们将子线程的任务交给FutureTask,然后开启一个子线程,再从FutureTask中获取结果。

    FutureTask<V> implements RunnableFuture<V> RunnableFuture<V> extends Runnable, Future<V>

    @Test
    public void test3() throws Exception {
        Long startTime = System.currentTimeMillis();
        Object[] objects = new Object[2];
    
        // FutureTask需要传入一个Callable接口
        FutureTask<String> futureTask1 = new FutureTask(new Callable() {
            @Override
            public String call() throws Exception {
                log.info("thread1开始执行");
                String result1 = Computer.longTimeDoSomething();
                log.info("thread1执行完毕,结果={}", result1);
                return result1;
            }
        });
    
        Thread thread1 = new Thread(futureTask1);
        thread1.start();
    
        FutureTask<Long> futureTask2 = new FutureTask(()->{
            log.info("thread2开始执行");
            Long result2 = Computer.complexCompute();
            log.info("thread2执行完毕,结果={}", result2);
            return result2;
        });
        Thread thread2 = new Thread(futureTask2);
        thread2.start();
      
            // 方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线程,直到任务执行完毕
        objects[0] = futureTask1.get();
        objects[1] = futureTask2.get();
    
        Long endTime = System.currentTimeMillis();
        log.info("耗时={}毫秒,结果={},{}", (endTime - startTime), objects[0], objects[1]);
    }
    
    [Thread-1]thread1开始执行
    [Thread-2]thread2开始执行
    [Thread-2]thread2执行完毕,结果=100
    [Thread-1]thread1执行完毕,结果=DoSomething-Result
    [    main]耗时=5011毫秒,结果=DoSomething-Result,100
    

    thread1和thread2可以同时开始执行,最终也可以拿到两个结果。注意,如果将futureTask1.get()方法迁移到thread1.start()方法下面立即执行,就达不到这个效果,这样就和上面一样,串行执行

    JDK8-CompletableFuture

    相关文章

      网友评论

          本文标题:Future介绍

          本文链接:https://www.haomeiwen.com/subject/vrjadktx.html