线程池管理线程使用心得

整改背景

通讯项目原有架构 springboot 2.5 netty4.x 构造一套接受设备端16进制报文的解析服务器

内部的每个解析协议解析都会新建一个线程执行任务,由于解析协议比较多,每次任务新建线程,

线程众多,管理这些线程的状态想到了使用线程池。

1.配置线程池

//线程池配置
/**
 * IO密集型任务 = 一般为2*CPU核心数(常出现于线程中:数据库数据交互、文件上传下载、网络数据传输等等)
 * CPU密集型任务 = 一般为CPU核心数+1(常出现于线程中:复杂算法)
 * 混合型任务 = 视机器配置和复杂度自测而定
 */
public static int cpuCodeSize = Runtime.getRuntime().availableProcessors();
public static int corePoolSize = cpuCodeSize * 2;
/**
 * public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,
 * TimeUnit com.unit,BlockingQueue<Runnable> workQueue)
 * corePoolSize用于指定核心线程数量
 * maximumPoolSize指定最大线程数
 * keepAliveTime和TimeUnit指定线程空闲后的最大存活时间
 * workQueue则是线程池的缓冲队列,还未执行的线程会在队列中等待
 * 监控队列长度,确保队列有界
 * 不当的线程池大小会使得处理速度变慢,稳定性下降,并且导致内存泄露。如果配置的线程过少,则队列会持续变大,消耗过多内存。
 * 而过多的线程又会 由于频繁的上下文切换导致整个系统的速度变缓——殊途而同归。队列的长度至关重要,它必须得是有界的,这样如果线程池不堪重负了它可以暂时拒绝掉新的请求。
 * ExecutorService 默认的实现是一个无界的 LinkedBlockingQueue。
 */
//LinkedBlockingQueue  列长度必须有界最大为Integer.MAX_VALUE,这里设置为1000
//handler策略模式:
//1.AbortPolicy 拒绝策略:抛出运行时异常RejectedExecutionException;策略丢弃任务,并抛出异常(默认策略)
//2.DiscardPolicy 拒绝策略:不能执行的任务将被丢弃;这种策略什么都没做
//3.DiscardOldestPolicy 拒绝策略:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序
//4.CallerRunsPolicy 拒绝策略:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

public static RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
//自定义线程池
public static Executor executor = new ThreadPoolExecutor(corePoolSize, corePoolSize + 1, 10l, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(1000), handler);

2.使用线程池

这里线程池任务用到submit、execute也可以,两者区别是submit有返回值execute无返回值

Future<String> submit = pool.submit(() -> {
    GNSSServer.FSQLLogThreadArray.AddQueue(sql);
    return "success";
});

try {
    if (submit.get().equals("success")) {
        System.out.println("-------线程池submit------success-----------");
    }
} catch (Exception e) {
    System.out.println("___________线程池submit______error______________");
}

3.监视线程

把任务加入线程池之后,通过线程池api打印线程池当前运行状态

ThreadPoolExecutor pool = (ThreadPoolExecutor) ServerApplication.executor;
log.info("++++++++++++++++服务端读取完毕+++++++++++++++");
log.info("++++++++++++++++当前排队线程数"+ pool.getQueue().size());
log.info("++++++++++++++++当前活动线程数"+ pool.getActiveCount());
log.info("++++++++++++++++执行完成线程数"+ pool.getCompletedTaskCount());
log.info("++++++++++++++++总线程数(排队线程数 + 活动线程数 + 执行完成线程数)"+ pool.getTaskCount());

4.线程池工作流程图

5.线程池线程生命周期   

设:我们有一个coreSize=10,maxSize=20,keepAliveTime=60s,queue=40
1、池初始化时里面没有任何线程。
2、当有一个任务提交到池就创建第一个线程。
3、若继续提交任务,有空闲线程就调拨空闲线程来处理任务?若没有线程空闲则再新建一个线程来处理,如此直到coreSize。【预热阶段
4、若继续提交任务,有空闲线程就调拨空闲线程来处理任务,如果没有空闲线程(10个)则将任务缓存到queue中排队等待。
5、若继续提交任务,而已有线程不空闲,且queue也满了,则新建线程,并将最新的任务优先提交给新线程处理。
6、若继续提交任务,且所有线程(20个)仍不空闲,queue也是满的,此时就会触发池的拒绝机制。
8、一旦有任何线程空闲下来就会从queue中消费任务,直到queue中任务被消费完。
9、当总忙碌线程个数不超过coreSize时,闲暇线程休息keepAliveTime过后会被销毁。
10、而池中一直保留coreSize个线程存活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值