springboot 整合线程池(包涵各参数设置说明)

正文

项目代码可到我的git下载,对您有帮助的话麻烦点个星星,爱你哦!

先上结构图

在这里插入图片描述

代码从上往下

ThreadPoolConfig

package com.threadpool.demo.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author HJH
 * @Description: 线程池配置类
 * @date 2019/8/1 13:44
 *  tasks :每秒的任务数
 *  taskcost:每个任务花费时间,假设为0.1s
 *  responsetime:系统允许容忍的最大响应时间,假设为1s
 */
@Configuration
@EnableAsync
public class ThreadPoolConfig {

    /**
     *   每秒需要多少个线程处理?
     *   tasks/(1/taskcost)
     */
    private int corePoolSize = 3;

    /**
     * 线程池维护线程的最大数量
     * (max(tasks)- queueCapacity)/(1/taskcost)
     */
    private int maxPoolSize = 3;

    /**
     * 缓存队列
     * (coreSizePool/taskcost)*responsetime
     */
    private int queueCapacity = 10;

    /**
     * 允许的空闲时间
     * 默认为60
     */
    private int keepAlive = 100;

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(corePoolSize);
        // 设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        // 设置队列容量
        executor.setQueueCapacity(queueCapacity);
        // 设置允许的空闲时间(秒)
        //executor.setKeepAliveSeconds(keepAlive);
        // 设置默认线程名称
        executor.setThreadNamePrefix("thread-");
        // 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }


}

ThreadController

package com.threadpool.demo.controller;


import com.threadpool.demo.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * @author HJH
 * @Description: 线程测试控制器
 * @date 2019/8/1 13:45
 */
@RestController
public class ThreadController {

    @Autowired
    private AsyncService asyncService;

    @GetMapping("/thread")
    public void thread() {
        //调用service层的任务
        asyncService.executeAsync();
    }

}

AsyncServiceImpl

package com.threadpool.demo.service.impl;


import com.threadpool.demo.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * @author HJH
 * @Description: 实现
 * @date 2019/8/1 13:48
 */
@Service
public class AsyncServiceImpl implements AsyncService {

    private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);


    @Async("taskExecutor")
    @Override
    public void executeAsync() {
        logger.info("start executeAsync");
        try {
            System.out.println("当前运行的线程名称:" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("end executeAsync");
    }

}

AsyncService

package com.threadpool.demo.service;

/**
 * @author HJH
 * @Description: 线程测试service
 * @date 2019/8/1 13:47
 */
public interface AsyncService {

    void executeAsync();

}

运行结果

在这里插入图片描述
一共执行了6次,获取到的线程是有序的。ThreadPoolConfig里的参数我是要在本地跑随便设置的,值设得太大的话会抛异常哦!

如何设置线程池的各个参数?

默认值

corePoolSize=1
queueCapacity=Integer.MAX_VALUE
maxPoolSize=Integer.MAX_VALUE
keepAliveTime=60s
allowCoreThreadTimeout=false
rejectedExecutionHandler=AbortPolicy()

如何设置

需要根据几个值来决定

tasks :每秒的任务数,假设为500~1000
taskcost:每个任务花费时间,假设为0.1s
responsetime:系统允许容忍的最大响应时间,假设为1s

做几个计算:
1,corePoolSize = 每秒需要多少个线程处理?

threadcount = tasks/(1/taskcost) =tasks*taskcost =  (500~1000)*0.1 = 50~100 个线程。corePoolSize设置应该大于50
根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可

2, queueCapacity = (coreSizePool/taskcost)*responsetime

计算可得 queueCapacity = 80/0.1*1 = 80。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行
切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。

3, maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)

计算可得 maxPoolSize = (1000-80)/10 = 92
(最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数
理解:

1、如果当前线程池的线程数还没有达到核心线程数大小,即 poolSize < corePoolSize ,无论是否有空闲的线程,系统回新增一个线程来处理新提交的任务;

2、如果当前线程池的线程数大于或者等于核心线程数大小,即 poolSize >= corePoolSize,且任务队列未满时,将提交的任务提交到阻塞队列中,等待处理workQueue.offer(command);

3、如果当前线程池的线程数大于或者等于核心线程数大小,即 poolSize >= corePoolSize,且任务队列已满时,分以下两种情况:

3.1、poolSize < maximumPoolSize ,新增线程来处理任务;

3.2、poolSize = maximuxPoolSize ,意味中线程池的处理能力已经达到极限,此时会拒绝增加新的任务,至于如何拒绝,取决于RejectedExecutionHandler

4,rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
在这里插入图片描述
5,keepAliveTimeallowCoreThreadTimeout采用默认通常能满足

以上都是理想值,实际情况下要根据机器性能来决定。如果在未达到最大线程数的情况机器cpu load已经满了,则需要通过升级硬件和优化代码,降低taskcost来处理。

最后:祝大家开开心心每一天。

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值