java并发--- 转:Callable、Future和FutureTask

转载地址:https://blog.csdn.net/javazejian/article/details/50896505

创建线程的方式有两种,一种是实现Runnable接口,另一种是继承Thread,但是这两种方式都有个缺点,那就是在任务执行完成之后无法获取返回结果,从JAVA SE 5.0开始引入了Callable和Future,通过它们构建的线程,在任务执行完成后就可以获取执行结果,今天我们就来聊聊线程创建的第三种方式,那就是实现Callable接口。

Callable的接口定义如下:

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

该接口声明了一个名称为call()的方法,同时这个方法可以有返回值V,也可以抛出异常。

Future

实现Callable接口,可以有返回值,代码如下:

@Slf4j
public class FutureExample1 {
    static class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            log.info("do someting in callable");
            Thread.sleep(5000);
            return "Done";
        }
    }
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(new MyCallable());
        log.info("do someting in main");
        Thread.sleep(1000);
        String result = future.get();
        log.info("result:{}", result);
        executorService.shutdown();
    }
}

FutureTask

我们先来看看FutureTask的实现,

public class FutureTask<V> implements RunnableFuture<V> {

FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:

public interface RunnableFuture<V> extends Runnable, Future<V> {  
    void run();  
}  
分析:FutureTask除了实现了Future接口外还实现了Runnable接口,因此FutureTask也可以直接提交给Executor执行。 当然也可以调用线程直接执行(FutureTask.run())。接下来我们根据FutureTask.run()的执行时机来分析其所处的3种状态:
(1)未启动,FutureTask.run()方法还没有被执行之前,FutureTask处于未启动状态,当创建一个FutureTask,而且没有执行FutureTask.run()方法前,这个FutureTask也处于未启动状态。
(2)已启动,FutureTask.run()被执行的过程中,FutureTask处于已启动状态。

(3)已完成,FutureTask.run()方法执行完正常结束,或者被取消或者抛出异常而结束,FutureTask都处于完成状态。


下面我们再来看看FutureTask的方法执行示意图(方法和Future接口基本是一样的,这里就不过多描述了)


分析:
(1)当FutureTask处于未启动或已启动状态时,如果此时我们执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或者抛出异常。
(2)当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会执行。

当FutureTask处于已启动状态时,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果任务取消成功,cancel(...)返回true;但如果执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时cancel(...)返回false。

 使用Callable+FutureTask获取执行结果,代码如下:

@Slf4j
public class FutureTaskExample {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("do something in callable");
                Thread.sleep(5000);
                return "Done";
            }
        });
        new Thread(futureTask).start();
        log.info("do something in main");
        Thread.sleep(1000);
        String result = futureTask.get();
        log.info("result:{}", result);
    }
}

执行结果如下:

15:13:05.806 [main] INFO concurrency.example.futureForkJoinBlockingQueue.FutureTaskExample - do something in main
15:13:05.812 [Thread-0] INFO concurrency.example.futureForkJoinBlockingQueue.FutureTaskExample - do something in callable
15:13:10.812 [main] INFO concurrency.example.futureForkJoinBlockingQueue.FutureTaskExample - result:Done

猜你喜欢

转载自blog.csdn.net/weianluo/article/details/80194974
今日推荐