美文网首页
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