参考:https://www.cnblogs.com/fengsehng/p/6048609.html
这篇博客介绍得很详细;
Callable,简单来说,Callable就是我们以前写的Runnable,就是一个线程要执行的具体程序块,告诉线程要干什么相较于Runnable他可以使用泛型定义返回值,我们可以方便的获取到线程的执行结果;
@Override public ThreeDModelPO call() throws Exception { return null; }
Future,他可以控制Callable,方便我们随时查看线程的状态,终止,获取返回结果等操作;
1)判断任务是否完成;
2)能够中断任务;
3)能够获取任务执行结果。
ExecutorService,类似有点线程池吧;我们可以使用默认的的方法创建线程池,也可以自定义线程池的数量
ExecutorService executorServicee = Executors.newFixedThreadPool(threadNum);
Executors.newCachedThreadPool();
我就用过这两个方法,具体可以查看java-api的文档,这些是java5出来的,所以直接查看api6中文版还是挺方便的;
以下是我用到的代码:
/**
* 下载资源,不分先后下载
*
* @param threadNum 线程池初始化线程数
* @param prototypes 需要下载的原型集合
* @return 下载成功的原型
*/
public List<ThreeDModelPrototypePO> downAssets(int threadNum, List<ThreeDModelPrototypePO> prototypes) {
long startTime = System.currentTimeMillis();
/**
* 定义线程池中的数量
*/
ExecutorService executorServicee = Executors.newFixedThreadPool(threadNum);
List<Future<ThreeDModelPO>> futures=new ArrayList<>();
prototypes.forEach(pro -> {
Future<ThreeDModelPO> future = executorServicee.submit(new DownModelCallable(pro));
futures.add(future);
});
while(true){
List<Boolean> successList=new ArrayList<>();
for(int i=0;i<futures.size();i++){
//如果有一个没有执行成功,则继续等待
if(futures.get(i).isDone()){
successList.add(true);
}
}
//如果执行完成的数量跟添加的线程数一样,则所有线程都执行完了
if(successList.size()==futures.size()){
log.info("下载完成,执行完成,用时:"+(System.currentTimeMillis()-startTime));
executorServicee.shutdown();
break;
}
}
return prototypes;
}
不要在 submit后马上使用future.get()结果,会阻塞线程的,这样的使用方式和不使用线程没什么两样;
/**
* 下载进程
* 下载成功,返回封装好了的模型对象
*/
class DownModelCallable implements Callable<ThreeDModelPO> {
public DownModelCallable() {
}
private ThreeDModelPrototypePO prototype;
public DownModelCallable(ThreeDModelPrototypePO prototype) {
this.prototype = prototype;
}
@Override
public ThreeDModelPO call() throws Exception {
//下载模型和封装
return null;
}
}