JAVA多线程进阶篇 10、JUC之Callable Future FutureTask

了解线程池之前需要对线程定义的方法进一步补充,可以参见《JAVA多线程基础篇 2、如何创建线程》

1. Callable

在JDK5之后,增加了Callable接口,实现该接口的类,可以类似Runnable方法,在多线程环境中运行,并且返回运行结果。

public class CallableA implements Callable<String>{

    @Override
    public String call() throws Exception {
        //模拟耗时计算
        Thread.sleep(1000);
        return "您好 ! 蛋糕做好了";
    }
}

2. Future与线程池配合运行

调用Callable对象,需要配合Future和线程池。
线程池提交Callable任务后,会返回Future对象.此时Future对象只是一个占位符,就好像去订蛋糕,蛋糕店会给你一张提货小票。
当调用future.get()方法时,才会阻塞直到获取结果。

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(new CallableA());
        System.out.println(future.get());
        executorService.shutdown();
    }

运行结果:

您好 ! 蛋糕做好了

3. FutureTask

FutureTask非常灵活。它同时实现了Runnable接口和Callable接口,,还实现了Future接口。所以FutureTask既能当做一个Runnable直接被Thread执行,也能作为Future用来得到Callable的计算结果。

3.1 FutureTask作为线程单独运行

public class FutureTaskTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        Callable<String> makecake = new Callable<String>(){
            @Override
            public String call() throws Exception {
                return "蛋糕做好了";
            }
        };

        FutureTask<String> task = new FutureTask(makecake);

        new Thread(task).start();

        System.out.println(task.get());

    }
}

运行结果:

您好 ! 蛋糕做好了

3.2 FutureTask与线程池配合运行

也可以将FutureTask提交到线程池运行,然后从FutureTask里取出Future结果。
因为FutureTask即实现了Runnable接口和Callable,还实现了Future接口。


public class FutureTaskTest2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        Callable<String> makecake = new Callable<String>(){
            @Override
            public String call() throws Exception {
                return "蛋糕做好了";
            }
        };

        FutureTask<String> task = new FutureTask(makecake);

        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.submit(task);

        System.out.println(task.get());
    }
}

运行结果:

您好 ! 蛋糕做好了

总结

除了Runnable接口外,Callable结合线程池、以及FutureTask类都可以提交线程任务。

多线程系列在github上有一个开源项目,主要是本系列博客的实验代码。

https://github.com/forestnlp/concurrentlab

如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。

您的支持是对我最大的鼓励。


版权声明:本文为EndlessProcess原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。