概述
之前在Java随笔-线程创建中指出线程创建方式只有两种:Thread扩展类、Runnable实现类,并没有把Callable与FutureTask算成一种,也没有解释原因,本文就说明一下为什么通过Callable与FutureTask创建线程不能算一种。
使用
public class CallableDemo {
    private static class CallableUse implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            // 再次输出当前线程名称
            System.out.println(Thread.currentThread().getName());
            System.out.println("这是callable的实现");
            Thread.sleep(1000);
            System.out.println("线程睡了1000ms后callable的实现");
            return 11;
        }
    }
    public static void main(String[] args) {
        // 输出当前线程名称
        System.out.println(Thread.currentThread().getName());
        CallableUse callableUse = new CallableUse();
        FutureTask<Integer> futureTask = new FutureTask<>(callableUse);
        // 开启线程
        new Thread(futureTask).start();
        try {
            // 输出返回值 
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
 
结果输出:
main
Thread-0
这是callable的实现
线程睡了1000ms后callable的实现
11
结束
 
创建步骤:
- 创建Callable实现类,并指定泛型,即返回值类型。
 - 以Callable实现类实例为参数创建FutureTask实例,同样需要指定泛型。
 - 将FutureTask实例作为Thread参数开启线程。
 
优势
- 通过Callable与FutureTask创建线程,然后调用futureTask.get()可以获取Callable实现类的返回值。

使用Thread和Runnable时,run方法是没有返回值的,若是需要拿到结果还需通过其他方式,而Callable的call() 是可以直接返回结果。 - 异步。通过futureTask.get()获取返回值时,即使call()中 Thread.sleep(1000),依然会等所有事情处理完成后再返回结果。此时会该线程会阻塞主线程,等该线程完成后,主线程才会继续执行,而Thread和Runnable线程中阻塞后并不影响主线程执行。
 
不算新的启动线程方式原因
通过Callable与FutureTask启动线程是Runnable启动线程的一种。
- Callable和Runnable基本一致。
 
@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;
}
 
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface {@code Runnable} is used
     * to create a thread, starting the thread causes the object's
     * {@code run} method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method {@code run} is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
 
- FutureTask是Runnable的一种。
首先FutureTask实现类RunnableFuture。 
public class FutureTask<V> implements RunnableFuture<V> {...}
 
然后RunnableFuture实现了Runnable。
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}
 
注:Java中接口可以多继承。
- Thread构造中没有FutureTask参数。

Thread构造有很多,但是没有以FutureTask为参数的,但使用时可以像使用Runnable那样使用,故FutureTask是Runnable是一种。 
综上所诉,通过Callable与FutureTask创建线程是实现Runnable接口创建线程中的一种方式,所以通过Callable与FutureTask创建线程不算是新的创建线程方式。










