核心线程数设定一般原则:
cup密集型: CPU核数 + 1 (Runtime.getRuntime().availableProcessors()动态获取CPU核数)
io密集型:CPU核数 * 2
线程池现成添加步骤:
1,提交任务数>= 核心线程数 将任务添加到队列
2,队列满了以后 && 提交任务数<=最大线程数 则新开线程到最大线程数
3,最大线程满了则执行拒绝策略
注意:如果队列选择为无界队列LinkedBlockingQueue( Integer.MAX_VALUE)则最大线程数无意义。
package com.service.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com..framework.common.utils.CheckUtils;
import com....cache.RegionDeviceCache;
import com....client.OrganizationFeignClient;
import com....client.VMSOMSFeignClient;
import com....common.constant.CommonConstants;
import com....common.enums.GlobalThreadPool;
import com....dto.response.OrganizationResDTO;
import com....dto.response.OrganizationTreeDTO;
import com....dto.response.RegionDeviceDTO;
import com....dto.statistic.RegionDeviceChartDTO;
import com....service.RegionDeviceService;
import com....utils.OrganizationUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
/**
* 区域设备在线统计
*
* @Author xiangchao
* @create 2020/8/4 19:27
*/
@Service
@Slf4j
public class RegionDeviceServiceImpl implements RegionDeviceService {
@Resource
private VMSOMSFeignClient vMSOMSFeignClient;
@Resource
private OrganizationFeignClient organizationClient;
/**
* 配置里自定义的区域设备在线统计的区域集合
*/
@Value("#{'${statics.region-device.area}'.split(',')}")
private List<String> areaList;
/**
* 区域设备统计默认数据为0
*/
private final static Integer AREA_TOTAL_EMPTY = 0;
/**
* 获取区域设备统计数据并放入缓存中
*
* @param areaList
*/
@Override
public void putIntoCacheOfRegionDevice(List<String> areaList) {
if (CheckUtils.isNullOrEmpty(areaList)) {
areaList = this.areaList;
}
// 执行远程调用获取数据-这儿使用线程安全的ConcurrentHashMap
Map<String, Object> result = Maps.newConcurrentMap();
CountDownLatch countDownLatch = new CountDownLatch(areaList.size());
// 开始构造缓存数据
for (String area : areaList) {
GlobalThreadPool.INSTANCE.execute(() -> {
handlerRegionDevice(area, result);
countDownLatch.countDown();
});
}
// 休息一会等待线程池任务执行完毕 countDownLatch.countDown()计数为0的时候
try {
countDownLatch.await();
} catch (InterruptedException e) {
log.error("线程池异常:[{}]", e.getMessage());
e.printStackTrace();
}
log.info("当前时间:【{}】,本次推送缓存数据为:【{}】,推送之前缓存数据大小为:【{}】",
LocalDateTime.now(), result, RegionDeviceCache.getAreaDeviceCache().size());
RegionDeviceCache.setAreaDeviceCache(CommonConstants.SIMPLE_TIME_DATE_FORMATTER.format(LocalDateTime.now()), result);
}
@Override
public RegionDeviceChartDTO getRegionDeviceChart(List<String> areaList) {
if (CheckUtils.isNullOrEmpty(areaList)) {
areaList = this.areaList;
}
RegionDeviceChartDTO regionDeviceChartDTO = RegionDeviceChartDTO.builder().build();
// 排序,Map.Entry<time, Map<areaName, num> 时间、区域名称、区域名称对应数量
List<Map.Entry<String, Map<String, Object>>> entryList = RegionDeviceCache.getAreaDeviceCache().asMap().entrySet()
.stream()
.sorted(Comparator.comparing(Map.Entry::getKey)) //按照时间排序
.collect(Collectors.toList());
// 横坐标数据 时间 2020-09-07 12:12 -> 12:12
regionDeviceChartDTO.setAbscissa(
entryList.stream()
.map(e -> CommonConstants.SIMPLE_TIME_MINUTE_FORMATTER.format(LocalDateTime.parse(e.getKey(), CommonConstants.SIMPLE_TIME_DATE_FORMATTER)))
.collect(Collectors.toList())
);
List<RegionDeviceChartDTO.AreaEntity> values = Lists.newArrayList();
// 根据区域名称拿到区域数据
areaList.forEach(e -> values.add(getArea(e, entryList)));
regionDeviceChartDTO.setValues(values);
return regionDeviceChartDTO;
}
/**
* 处理得到的数据并放入缓存
*
* @param area
* @param result
*/
private void handlerRegionDevice(String area, Map<String, Object> result) {
// 读取配置文件里面的区域名称 获取公共服务组织树接口 拿到对应的org_index 集合
List<OrganizationTreeDTO> organizationsTrees = organizationClient.getOrganizationsTree(CommonConstants.InterfaceParameter.ORGANIZATION_TYPE, area);
if (CheckUtils.isNullOrEmpty(organizationsTrees)) {
result.put(area, 0);
return;
}
// 递归找到orgIndex
Set<OrganizationResDTO> organizationResDTOS = OrganizationUtil.recursion(Sets.newConcurrentHashSet(), organizationsTrees, area);
Set<String> orgIndexList = organizationResDTOS.stream().map(OrganizationResDTO::getOrgIndex).collect(Collectors.toSet());
// 查询区域设备统计结果
List<RegionDeviceDTO> regionDeviceDTOList = vMSOMSFeignClient.getRegionDeviceCount(orgIndexList);
// 累加
int total = regionDeviceDTOList.stream().mapToInt(RegionDeviceDTO::getDeviceOnline).sum();
result.put(area, total);
}
/**
* 根据区域名称拿到区域数据
*
* @param area
* @return
*/
private static RegionDeviceChartDTO.AreaEntity getArea(String area, List<Map.Entry<String, Map<String, Object>>> entryList) {
RegionDeviceChartDTO.AreaEntity areaEntity = new RegionDeviceChartDTO.AreaEntity();
areaEntity.setArea(area);
List<Integer> list = Lists.newArrayList();
entryList.stream().map(Map.Entry::getValue).forEach(e ->
list.add(Objects.isNull(e.get(area)) ? AREA_TOTAL_EMPTY : Integer.parseInt(e.get(area).toString())));
areaEntity.setValues(list);
return areaEntity;
}
}
GlobalThreadPool.java
package com.unisinsight.uss.bcs.common.enums;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.unisinsight.framework.common.utils.CheckUtils;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* <h1>线程池枚举单例</h1>
*/
public enum GlobalThreadPool {
INSTANCE;
/**
* 线程池参数
*/
public static final int DEFAULT_CORE_SIZE = 8; // 线程数量
public static final int MAXIMUM_POOL_SIZE = 20; // 最大线程数量
public static final long KEEP_ALIVE_TIME = 30L; // 当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间
public static final int BLOCKING_QUEUE_SIZE = 100; // 任务队列,被提交但尚未被执行的任务
private final ThreadPoolExecutor pool;
// 私有构造器
GlobalThreadPool() {
pool = new ThreadPoolExecutor(DEFAULT_CORE_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(BLOCKING_QUEUE_SIZE),
new ThreadFactoryBuilder().setNameFormat("thread-pool-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy());//拒绝策略,新任务交由调用者所在的线程来执行
}
// 异步执行方法
public void execute(Runnable runnable) {
if (CheckUtils.isNullOrEmpty(runnable)) {
return;
}
pool.execute(runnable);
}
}