Java -JDK、Spring boot、多线程创建

  • 俗话说 双拳难敌4手,人多好办事;单一个人干活比较吃力的时候,这时我们就需要摇人儿了。
  • 当单线程执行任务效率较低时,我们就考虑使用多线程解决问题,同时注意数据同步问题。

线程池参数:

  • corePoolSize 线程池基本线程数量,打底数量,不会被回收,长期维护的线程
  • maximumPoolSize 最大线程数量,当前 核心线程、等待队列都满时,线程池会创建线程运行直到达到最大线程池数
  • keepAliveTime 非核心线程的空闲线程的存活时长
  • TimeUnit 存活时长单位,如 TimeUnit.MILLISECONDS
  • BlockingQueue<> 等待队列,核心线程数满时,后提交到线程池的线程加入队列排队等待
  • RejectedExecutionHandler 当线程数量超过,最大线程数+队列数时,再次进入线程池的线程会触发拒绝策略

手动创建线程池:

  • 一般建议不丢弃任务,丢弃可能少数据,采用策略 CallerRunsPolicy();返回发起线程继续执行,一般是main 线程
  • 线程池的核心线程数,一般根据CPU 数,以及 阻塞系数确定,0~1,系数越高,执行任务时间越长
  • 分为 IO型、CPU型,根据情况具体配置
	private static final int core= Runtime.getRuntime().availableProcessors();
	private static final int waitCount = 20;

    private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor
    			 (core,
    			  core + waitCount, 
    			  60*10, TimeUnit.SECONDS,
                  new ArrayBlockingQueue<>(waitCount),
                  new CustomizableThreadFactory("线程池-"),
            	  new ThreadPoolExecutor.CallerRunsPolicy());

jdk创建,场景一 :

  • 执行较多耗时任务,不需要实时刷新状态,任务完成修改数据状态,前端查询更新
  • 这里都是,比如接口调用一次,执行到多线程调用,就会往线程池添加一个执行任务线程,或者由空闲线程接手
//不需要返回值异步执行时
pool.execute(() -> {
            materialService.toConvertForAdd(trainInformation);
            esHandle(trainInformation);
});
//需要返回值时
Callable<Boolean> c1 = ()-> exampleServcie.cleanHouse(1);
Callable<Boolean> c2 = ()-> exampleServcie.cleanHouse(2);
Callable<Boolean> c3 = ()-> exampleServcie.cleanHouse(3);
Callable<Boolean> c4 = ()-> exampleServcie.cleanHouse(4);
List<Future<Boolean>> futures = poolExecutor.invokeAll(Arrays.asList(c1, c2, c3, c4));
futures.forEach(e->{
    try {
        System.out.println(e.get());
    } catch (InterruptedException | ExecutionException ex) {
        ex.printStackTrace();
    }
});

Spring boot 工具类运用

  • ThreadPoolTaskExecutor
@EnableAsync
@Configuration
public class PoolConfig {

    /**
     * 服务核数
     */
    private static final int CORE = Runtime.getRuntime().availableProcessors();

    /**
     * - CPU密集型,eg: 加密、解密、压缩、计算
     * - 高并发、任务执行时间短业务,线程数可以设置为CPU核数+1,减少线程上下文切换
     * - 默认设置策略 CallerRunsPolicy(),让发出线程继续执行任务,不考虑任务顺序,主数据不丢失
     * @return Executor
     */
    @Bean("cpuDefaultThreadPool")
    public Executor cpuDefaultThreadPool(){
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(CORE+1);
        taskExecutor.setQueueCapacity(20);
        taskExecutor.setMaxPoolSize(CORE+21);
        taskExecutor.setKeepAliveSeconds(60*10);
        taskExecutor.setThreadNamePrefix("cpuPool-");
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.initialize();
        return taskExecutor;
    }

    /**
     * - 耗时型,eg : 数据库、文件读写,网络通信等任务 -> 不会特别消耗 CPU资源,但是IO 操作很耗时间
     * - 默认设置策略 CallerRunsPolicy(),让发出线程继续执行任务,不考虑任务顺序,主数据不丢失
     * - blockingCoefficient 阻塞系数
     * @return Executor
     */
    @Bean("ioDefaultThreadPool")
    public Executor ioDefaultThreadPool(){
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //每个任务80%的时间处于阻塞状态而只有10%的时间在干活
        //保守值cpu数量的2倍
        double blockingCoefficient =0.8;
        int poolSize = (int) (CORE / (1- blockingCoefficient));
        taskExecutor.setCorePoolSize(poolSize);
        taskExecutor.setQueueCapacity(20);
        taskExecutor.setMaxPoolSize(poolSize+20);
        taskExecutor.setKeepAliveSeconds(60*30);
        taskExecutor.setThreadNamePrefix("ioPool-");
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.initialize();
        return taskExecutor;
    }

}

普通运用

@Autowired
ThreadConfig threadConfig;

threadConfig.cpuDefaultThreadPool();
   @Autowired
   private ThreadConfig threadConfig;

   @GetMapping("/test")
   public void test(){
       List<Integer> test = getBatchListTest();
       List<List<Integer>> lists = Lists.partition(test, 100);
       Executor executor = threadConfig.getExecutor();
       List<CompletableFuture> results = new ArrayList<>();
       for (List<Integer> list : lists) {
           CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
               toDo(list);
               return "";
           }, executor);
           results.add(future);
       }
       CompletableFuture.allOf(results.toArray(new CompletableFuture[]{})).join();
   }

    List<Integer> getBatchListTest(){
        List<Integer> res = new LinkedList<>();
        for (int i = 0; i < 1000; i++) {
            res.add(i);
        }
        return res;
    }

    void  toDo(List<Integer> list){
        System.out.println("线程:"+Thread.currentThread().getId()+"集合:"+list.size());
    }
@Async("cpuDefaultThreadPool")
CompletableFuture<Boolean> cleanHouseAsync(Integer range);
@Override
public CompletableFuture<Boolean> cleanHouseAsync(Integer range) {
    try {
        Thread.sleep(1000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("Async: 打扫完了"+range+"号房间");
    return CompletableFuture.completedFuture(true);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值