public void weatherConditionList(String uniqueId) {
//可用CPU数
int availableProcessors = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(availableProcessors/2 + 1, availableProcessors/2 + 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(availableProcessors * 10000),
new ThreadFactoryBuilder().setNameFormat("weather-Condition-pool-Thread-%d").build(),
new ThreadPoolExecutor.AbortPolicy());
bizLogger.info("天气实况查询开始:uniqueId="+uniqueId);
try{
//查询所有租户绑定的城市id
List<String> cityIdList= adsOwnershipCityRelDao.selectCity(null);
if (CollectionUtils.isEmpty(cityIdList)){
return;
}
//countDownLatch总数为查出来的城市数量,用来保证线程全部执行完之后再执行insert操作
CountDownLatch countDownLatch=new CountDownLatch(cityIdList.size());
List<AdsWeather> list=Collections.synchronizedList(new ArrayList<AdsWeather>());
for (String cityId:cityIdList) {
threadPoolExecutor.execute(()->{
//根据cityId查询天气实况
AdsWeather ods= weatherCondition(cityId);
if (ods!=null){
list.add(ods);
}
//每次减一
countDownLatch.countDown();
});
}
//当countDownLatch等于0才能往下走
countDownLatch.await();
if (!CollectionUtils.isEmpty(list)){
//将天气实况存入数据库
adsWeatherDao.batchInsert(list);
}
}catch (Exception e){
bizLogger.error("天气实况批量查询报错",e);
}finally {
threadPoolExecutor.shutdown();
}
bizLogger.info("天气实况查询结束:uniqueId="+uniqueId);
}
CountDownLatch卡死问题:
一、线程池拒绝策略如果用的不是AbortPolicy,如果阻塞队列满了新的任务会被抛弃而且不抛弃异常,那countDownLatch永远不会等于0, countDownLatch.await()会一直阻塞。
拒绝策略
AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行
CallerRunsPolicy:调用者运行(让调用者线程执行任务,作为额外的线程执行任务,非线程池内部线程),不抛任务和异常,而是将任务回退给调用者,从而降低新任务的流量
DiscardOldPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交
DiscardPolicy:直接丢弃任务,不处理也没有异常。如果允许任务丢失,这是最好的解决方式
二、线程执行时报错,而多线程抛出的异常无法被正常捕获,这样countDownLatch.countDown()也会一直阻塞
public void weatherConditionList(String uniqueId) {
//可用CPU数
int availableProcessors = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(availableProcessors/2 + 1, availableProcessors/2 + 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(availableProcessors * 10000),
new ThreadFactoryBuilder().setNameFormat("weather-Condition-pool-Thread-%d").build(),
new ThreadPoolExecutor.AbortPolicy());
bizLogger.info("天气实况查询开始:uniqueId="+uniqueId);
try{
//查询所有租户绑定的城市id
List<String> cityIdList= adsOwnershipCityRelDao.selectCity(null);
if (CollectionUtils.isEmpty(cityIdList)){
return;
}
//countDownLatch总数为查出来的城市数量,用来保证线程全部执行完之后再执行insert操作
CountDownLatch countDownLatch=new CountDownLatch(cityIdList.size());
List<AdsWeather> list=Collections.synchronizedList(new ArrayList<AdsWeather>());
for (String cityId:cityIdList) {
threadPoolExecutor.execute(()->{
//这里抛出的异常没有被正常捕获
int a=10/0;
//根据cityId查询天气实况
AdsWeather ods= weatherCondition(cityId);
if (ods!=null){
list.add(ods);
}
//每次减一
countDownLatch.countDown();
});
}
//当countDownLatch等于0才能往下走
countDownLatch.await();
if (!CollectionUtils.isEmpty(list)){
//将天气实况存入数据库
adsWeatherDao.batchInsert(list);
}
}catch (Exception e){
bizLogger.error("天气实况批量查询报错",e);
}finally {
threadPoolExecutor.shutdown();
}
}
解决办法在线程内部try catch,在finally里执行减一操作
public void weatherConditionList(String uniqueId) {
//可用CPU数
int availableProcessors = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(availableProcessors + 1, availableProcessors + 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024),
new ThreadFactoryBuilder().setNameFormat("weather-Condition-pool-Thread-%d").build(),
new ThreadPoolExecutor.AbortPolicy());
bizLogger.info("天气实况查询开始:uniqueId="+uniqueId);
try{
//查询所有租户绑定的城市id
List<String> cityIdList= adsOwnershipCityRelDao.selectCity(null);
if (CollectionUtils.isEmpty(cityIdList)){
return;
}
//countDownLatch总数为查出来的城市数量,用来保证线程全部执行完之后再执行insert操作
CountDownLatch countDownLatch=new CountDownLatch(cityIdList.size());
List<AdsWeather> list=Collections.synchronizedList(new ArrayList<AdsWeather>());
for (String cityId:cityIdList) {
threadPoolExecutor.execute(()->{
try{
int i=10/0;
AdsWeather ods= weatherCondition(cityId);
if (ods!=null){
list.add(ods);
}
}catch (Exception e){
bizLogger.error("天气实况查询线程报错",e);
}finally {
//每次减一
countDownLatch.countDown();
}
});
}
//当countDownLatch等于0才能往下走
countDownLatch.await();
if (!CollectionUtils.isEmpty(list)){
//将天气实况存入数据库
adsWeatherDao.batchInsert(list);
}
}catch (Exception e){
bizLogger.error("天气实况批量查询报错",e);
}finally {
threadPoolExecutor.shutdown();
}
}