java多线程demo

核心线程数设定一般原则:

   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);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值