当使用线程池时,我们该如何获取结果呢?
1.ThreadPoolExecutor 获取执行结果
ThreadPoolExecutor 提供的 3 个 submit() 方法和 1 个 FutureTask 工具类来支持获得任务执行结果的需求
1.1.Submit
三个方法如下,其中区别如下:
- Future<?> submit(Runnable task):其中Runnable的run方法没有返回值,因此该方法获得的Future只能获得方法是否完成,类似于Thread.join();
- Future submit(Callable task):其中Callable方法有返回值,所以这个方法返回的 Future 对象可以通过调用其 get() 方法来获取任务的执行结果。这里调用get方法同样会阻塞,也就是说主线程会等待子线程执行完成并通过Future对象得到执行结果
- Future submit(Runnable task, T result):与 Future submit(Callable task)类似,只是其返回值是通过构造函数传递入Runnable的实现类,而 Future submit(Callable task)也可以通过构造函数传入然后通过方法return,但是Runnable接口是没有返回的,因此只能传入去修改,然后通过submit获得的Future对象去获得传入的T result
// 提交 Runnable 任务
Future<?> submit(Runnable task);
// 提交 Callable 任务
<T> Future<T> submit(Callable<T> task);
// 提交 Runnable 任务及结果引用
<T> Future<T> submit(Runnable task, T result);
Future有五个方法:
//任务取消
boolean cancel(boolean mayInterruptIfRunning);
//判断任务是否已取消
boolean isCancelled();
//判断任务是否已完成
boolean isDone();
//获得执行结果
V get() throws InterruptedException, ExecutionException;
//获得执行结果
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
两个get()都是阻塞式的,如果任务未执行完成,则调用该方法会阻塞调用线程直至完成。
2.FutureTask
FutureTask包含两个构造函数,其与 submit()方法类似,如下:
FutureTask(Callable<V> callable);
FutureTask(Runnable runnable, V result);
那如何使用 FutureTask 呢?FutureTask实现了Runnable和Future接口,由于实现了Runnable,意味着可以将其作为参数传给submit方法去执行也可以直接传给Thread对象去执行,执行之后,可以通过get方法获得执行结果
使用示例如下:
// 创建 FutureTask
FutureTask<Integer> futureTask
= new FutureTask<>(()-> 1+2);
// 创建线程池
ExecutorService es =
Executors.newCachedThreadPool();
// 提交 FutureTask
es.submit(futureTask);
// 获取计算结果
Integer result = futureTask.get();
FutureTask 对象直接被 Thread 执行的示例代码如下所示。相信你已经发现了,利用 FutureTask 对象可以很容易获取子线程的执行结果。
// 创建 FutureTask
FutureTask<Integer> futureTask
= new FutureTask<>(()-> 1+2);
// 创建并启动线程
Thread T1 = new Thread(futureTask);
T1.start();
// 获取计算结果
Integer result = futureTask.get();