在实际开发中,一般任务都有串行和并行之分。比如走完A步骤之后才能在走B步骤,这个属于串行。比如登录注册操作,只有先获取验证码,然后在使用验证码登录。又比如为了获取一个商品的价格,我们可以从多个渠道获取,从不同渠道获取商品价格是属于并行任务的,多个渠道之间完全没有任何的关系。这个时候我们一般都要搜集结果。
FutureTask就是非常适合这种情景的。
主要api有get,run,cancel等方法,在jdk1.7之前是依赖AbstractQueuedSynchronizer来实现的,1.7之后是使用直接原子操作,使用状态volatile state控制,较之前的版本改进很大,效率提升很多。
FutureTask相关源码介绍文章:
http://blog.csdn.net/xxxzhi/article/details/51453438
http://blog.csdn.net/wojiaolinaaa/article/details/50434817
深入分析volatile:
https://www.jianshu.com/p/7798161d7472
使用例子:
1:一般都要讲耗时任务放入到线程池中执行,而不是每次自己新建一个线程,需要做到对线程大小的可控。每台服务器都有最大线程限制的,需要将线程数量调整到最优。
/**
* 核心线程20个 最多50个线程 队列最大200,大于200的时候默认会抛出拒绝服务异常
*/
private ThreadPoolExecutor exec = new ThreadPoolExecutor(20, 50, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(200));
//任务执行工具封装类
public class ThirdCarOffersWorker<T> implements Callable<T> {
private ThirdCarInsureService carInsureService;
private ReqCarOffersDto reqCarOffersDto;
private UserVo userVo;
public ThirdCarOffersWorker(ThirdCarInsureService carInsureService, ReqCarOffersDto reqCarOffersDto, UserVo userVo) {
super();
this.carInsureService = carInsureService;
this.reqCarOffersDto = reqCarOffersDto;
this.userVo = userVo;
}
@SuppressWarnings("unchecked")
@Override
public T call() throws Exception {
// TODO Auto-generated method stub
T t = null;
t = (T) carInsureService.submitCarOffers(reqCarOffersDto, userVo);
return t;
}
}
//执行任务
List<AppResponseDto<ChannelQuotePriceIdDto>> resultList = new ArrayList<AppResponseDto<ChannelQuotePriceIdDto>>();
FutureTask<AppResponseDto<ChannelQuotePriceIdDto>> future= new FutureTask<AppResponseDto<ChannelQuotePriceIdDto>>(
new ThirdCarOffersWorker<AppResponseDto<ChannelQuotePriceIdDto>>(carInsureService, carOffersDto, userVo));
futureTasks.add(futureTask);
exec.submit(futureTask);
//获取结果
// 获取结果
for (FutureTask<AppResponseDto<ChannelQuotePriceIdDto>> tempFt : futureTasks) {
try {
resultList.add(tempFt.get());
} catch (InterruptedException | ExecutionException e) {
log.error("submitCarOffers Exception,Get CarOffers Result Error msg={}", e);
}
}