前文
Java5之前,线程是没有返回值的。Java5之后,可以写有返回值的任务了。
有返回值的任务必须实现Callable接口,没有返回值的任务实现Runnable接口。
执行Callable接口后,可以获得一个Future的一个对象,通过Feture的get方法就能获得返回的Object数据了。
正文
我们先看看具体的代码是如何操作的
//创建线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//定义Callable
Callable<String> callable = new Callable() {
@Override
public Object call() throws Exception {
List<String>stringList = new ArrayList<>();
for (int i = 0 ;i<10 ;i++){
String str = "第一个:".concat(String.valueOf(i));
stringList.add(str);
}
//返回result
return stringList;
}
};
//返回Future,实际上是FutureTask实例
Future<String> future = pool.submit(callable);
try {
System.out.println(future.get());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadUtils.shutdown(pool,3,TimeUnit.SECONDS);
再看看打印的结果,查看一下结果是否为我们需要的。
由上图可知。数据是对的,也是我们需要从线程池获取的数据。
由于我们是在自己的方法new的一个新的线程池,所以在用完后记得关掉。
在上图中shutDown用到的是封装的方法。将 .awaitTermination()也封装在方法内部。
/**
* 关闭线程池
*
* @param pool 线程池
* @param timeout 超时时间
* @param unit 超时时间单位
*/
public static void shutdown(ExecutorService pool, long timeout, TimeUnit unit) {
try {
//关闭线程池,已提交的任务继续执行,不再接收新的任务
pool.shutdown();
//等待所有的任务都结束(实时判断是否全完成),若所有任务都已完成,则返回true,若超时未完成,则返回false
if (!pool.awaitTermination(timeout, unit)) {
//超时的时候向线程池中所有的线程发出中断(interrupted)。
pool.shutdownNow();
}
} catch (InterruptedException e) {
// awaitTermination方法被中断的时候也中止线程池中全部的线程的执行。
System.out.println("awaitTermination interrupted: " + e);
pool.shutdownNow();
}
}
分析
线程池提供了三种方式获取线程执行结果,虽然使用方式不太一样,但内部都是依靠Callable+FutureTask来实现的。
第一种
Future submit(Callable task);
传入的参数为Callable,Callable.run()决定返回值。
第二种
Future<?> submit(Runnable task);
传入参数为Runnable,Runnable.run() 没有返回值,因此此时Future.get()返回null。
第三种
Future submit(Runnable task, T result);
传入参数除了Runnable,还有result,虽然Runnable.run() 没有返回值,但是最终Future.get() 将会返回result。
查看源码
由此,我们就可以获取到线程池的返回值了。