场景
我们在使用多线程的时候,会希望获取到线程的返回值,但是常规的继承Thread或者实现Runable接口是没有办法实现的,这时候我们就需要实现Callable接口结合Future或者FutureTask来达到目的了;
阐述
我们通过实现Callable接口获取线程的返回值的方法有两种:
1、Future:是一个最底层接口;
image2、FutureTask:是一个类,它实现了RunnableFuture接口,RunnableFuture接口又继承了Runnable和Future;
image代码
先上代码:
实现一个callable接口
public class TestCallable implements Callable {
private String msg;
public TestCallable(String msg) {
this.msg = msg;
}
public TestCallable() {
}
@Override
public Object call() throws Exception {
return "这个线程已经执行了" + msg;
}
}
先使用FutureTask
public class TestThreadPool {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
for (int i = 0; i < 20; i++) {
TestCallable callable = new TestCallable(i + "00");
FutureTask<String> task = new FutureTask<String>(callable);
threadPoolExecutor.submit(task);
try {
list.add(task.get());
}catch (Exception e){
e.printStackTrace();
}
}
System.out.println(list.size());
for(String s:list){
System.out.println(s);
}
}
}
再使用Future
public class TestThreadPool {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
for (int i = 0; i < 20; i++) {
TestCallable callable = new TestCallable(i + "00");
Future<String> future = threadPoolExecutor.submit(callable);
try {
list.add(future.get());
}catch (Exception e){
e.printStackTrace();
}
}
System.out.println(list.size());
for(String s:list){
System.out.println(s);
}
}
}
输出的结果都为:
image.png
分析
看上面代码发现基本发现好像都差不多,只是在调用submit传入的不一样,查看源码
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
代码中引用最终都指向了RunableFuture先前我们也发现了此接口是继承了Future和Runable接口的,所以它也可以指向Future引用;其实最终得到的都是一个Future,然后获取返回值;
扩展
这里使用的线程池并没有使用
Executors.newCachedThreadPool()
Executors.newFixedThreadPool(int n)
Executors.newScheduledThreadPool(int n)
Executors.newSingleThreadExecutor()
的方式创建线程,而是直接使用的
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize, long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue)
参数
corePoolSize:核心线程池大小
maximumPoolSize:最大线程池大小
keepAliveTime:线程最大空闲时间
TimeUnit :时间单位
BlockingQueue:线程等待队列
其实查看Executors源码可以发现,上面几种的创建方式底层都是用的ThreadPoolExecutor,之所以这样使用是因为我认为通过自定义线程池,我们可以更好的让线程池为我们所用,更加适应我的实际场景,但是这是建立在对线程池有一定的理解的基础上的;
网友评论