java多线程[10]:Callable和Future
来源:互联网 发布:好听淘宝名字大全 编辑:程序博客网 时间:2024/06/07 00:45
本篇要讨论的是Callable
接口和Future
接口。想要创建一个线程的话,除了实现Runnable
接口外,还可以实现Callable
接口,这样的话,在线程运行结束后可以返回一个运行结果。
在上一篇博客中我们讨论了如何使用线程池来启动线程,并对比了几种不同的线程池之间的差异。ExecutorService
的submit方法的定义如下
<T> Future<T> submit(Callable<T> task);
它提交一个实现了Callable
接口的类,这个类将作为一个线程异步地运行。submit方法的返回值是一个Future对象,如果想查询这个异步运行着的线程的运行状态或运行结果的话,可以通过这个Future对象来进行。Future接口包含以下方法
//取消任务boolean cancel(boolean mayInterruptIfRunning);//是否已取消boolean isCancelled();//是否已完成boolean isDone();//阻塞并等待线程的返回结果V get() throws InterruptedException, ExecutionException;//阻塞一定时间并等待线程的返回结果。如果超过时间后没有返回结果的话,则抛出TimeoutException异常V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
可以看得出来,Future接口包含了很多有用的方法可以控制或查询线程的运行状态。
下面来看一个例子。假设有一个list共包含从1到100这一百个数字,而我们要计算这一百个数字的和。为了提高计算速度,我将这个list拆分成三个小list并启动三个线程来并行计算他们的和,最终将三个线程返回的和加到一起,从而得到整个list的总和。这个线程要实现Callable接口,这样才能返回一个计算结果。下面是这个实现了Callable接口的类
import java.util.List;import java.util.concurrent.Callable;public class CallableWorker implements Callable<Integer> { private List<Integer> numberList = null; public CallableWorker(List<Integer> numberList) { this.numberList = numberList; } @Override public Integer call() throws Exception { int total = 0; for (int number : numberList) { total += number; } return total; }}
这个类接收一个List<Integer>
对象,然后计算这个集合内所有数字的和,并返回这个和。
下面通过一个线程池来启动三个CallableWorker
import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class FutureDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { List<Integer> list = new ArrayList<>(); for (int i = 1; i <= 100; i++) { list.add(i); } //拆分为三个集合 List<Integer> sublist1 = list.subList(0, 30); List<Integer> sublist2 = list.subList(30, 60); List<Integer> sublist3 = list.subList(60, 100); ExecutorService executorService = Executors.newFixedThreadPool(3); //启动三个异步线程来分别计算三个集合的和 Future<Integer> future1 = executorService.submit(new CallableWorker(sublist1)); Future<Integer> future2 = executorService.submit(new CallableWorker(sublist2)); Future<Integer> future3 = executorService.submit(new CallableWorker(sublist3)); //汇总三个线程的计算结果 int total = future1.get() + future2.get() + future3.get(); System.out.println("total = " + total); //关闭线程池,否则进程无法结束 executorService.shutdown(); }}
我使用Executors.newFixedThreadPool(3)
创建了一个包含三个线程的线程池,然后将list
对象拆分为三个sublist
对象并传递给三个CallableWorker
。使用executorService.submit()
方法提交一个线程,使用future1.get()
获取进程的返回结果。
最终求和的结果是5050。