Future

可以将 Future 视为保存结果的对象-但它可能暂时没有结果,它代表未来异步计算的结果。

提供了以下方法

// 试图取消此任务的执行。如果任务已完成、已取消或由于其他原因无法取消,则此尝试将失败。
// 如果成功,并且调用 cancel 时此任务尚未启动,则此任务不应运行。
// 如果任务已经启动,则 mayInterruptIfRunning 参数确定执行此任务的线程是否应该中断以尝试停止任务。
// 参数:mayInterruptIfRunning 如果执行此任务的线程应该被中断,则为true;否则,允许完成正在进行的任务
// 返回值:如果无法取消任务(通常是因为任务已正常完成),则为 false;反之亦然
boolean cancel(boolean mayInterruptIfRunning);

// 如果此任务在完成之前取消,则为 true
boolean isCancelled();

// 如果此任务已完成,则返回 true。
// 完成可能是由于正常终止、异常或取消——在所有这些情况下,此方法将返回 true。
boolean isDone();

// 此方法是个阻塞方法,会阻塞程序的运行来获取结果
// 如有必要,等待计算完成,然后检索其结果。
// CancellationException 如果计算被取消 
// ExecutionException 如果计算引发异常 
// InterruptedException 如果当前线程在等待时被中断
V get() throws InterruptedException, ExecutionException;

// 等待线程完成的最大等待时间
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

Callable<T>

两种创建线程的方法:一种是通过创建 Thread 类,另一种是通过使用 Runnable 创建线程。

但是,Runnable 缺少的一项功能是,当线程终止时(即 run() 完成时),我们无法使线程返回结果。为了支持此功能,Java 中提供了Callable 接口。

  • 实现 Callable 需要实现 call(), 里面是要执行的任务,并返回需要返回的结果。
  • call() 方法有可能引发异常,但 Runable 的 run() 不会。

我们看个 Future 和 Callable 的实例

import java.util.ArrayList;
import java.util.concurrent.*;

class Solution {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Solution solution = new Solution();
        int taskSize = 3;
        ExecutorService pool = Executors.newFixedThreadPool(taskSize);
        ArrayList<Future<Integer>> list = new ArrayList<>();
        for (int i = 0; i < taskSize; i++) {
            MyCallable myCallable = solution.new MyCallable();
            // 执行任务并获取 future 对象,并不会阻塞主进程
            Future<Integer> future = pool.submit(myCallable);
            list.add(future);
        }
        // 关闭线程池,关闭线程池时会等待里面线程执行完毕,但并不会阻塞主进程
        pool.shutdown();

        // 获取所有并发任务的运行结果
        for (Future<Integer> future : list) {
            // future.get() 会阻塞主进程
            System.out.println(future.get());
        }

    }

    public class MyCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            Thread.sleep(1000);
            return 1;
        }
    }
}

FutureTask

FutureTask 是 java 库提供的,该类型实现 Runnable 和 Future,并方便地将两种功能组合在一起。
可以通过为其构造函数提供 Callable 来创建 FutureTask。然后,将FutureTask 对象提供给 Thread 的构造函数以创建 Thread 对象。因此,间接地使用 Callable 创建线程。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class Solution {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Solution solution = new Solution();
        // 实例化 callable
        MyCallable myCallable = solution.new MyCallable();
        // 创建 futureTask
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
    }

    public class MyCallable implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            Thread.sleep(1000);
            return 1;
        }
    }
}

20180730145740512