线程池个人笔记总结

线程池的创建示例
@Override
    @Bean(name = "threadPool")
    public ThreadPoolTaskExecutor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        threadPool.setCorePoolSize(10);
        // 设置最大线程数
        threadPool.setMaxPoolSize(20);
        // 线程池所使用的缓冲队列
        threadPool.setQueueCapacity(10000);
        // 等待任务在关机时完成--表明等待所有线程执行完
        threadPool.setWaitForTasksToCompleteOnShutdown(true);
        // 线程池关闭的等待时间(默认为0)
        threadPool.setAwaitTerminationSeconds(60*5);
        // 非核心线程空闲的存活时间
        threadPool.setKeepAliveSeconds(1);
        // 线程名称前缀
        threadPool.setThreadNamePrefix("newton-thread-");
        // 线程池拒绝策略
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化线程
        threadPool.initialize();
        return threadPool;
    }
线程池参数解释
KeepAliveTime是什么,有什么用

我们设置的KeepAliveTime的时间是非核心线程空闲的存活时间,如果超过存活时间则会被销毁目的为了节省系统资源

拒绝策略的触发条件

当任务队列已满并且线程池中的线程数达到最大线程数时,新提交的任务就会触发拒绝策略

任务队列什么时候有数据

只有当线程池的使用线程数达到最大线程数时(包括核心和非核心线程数),此时新的任务才会进入任务队列等待执行

核心线程和非核心线程有什么区别

首先他们运行速度没有区别,行速度取决于CPU的调度和处理能力,以及任务本身的复杂性和计算量,他们区别主要在核心线程不会被销毁,除非线程池关闭,非核心线程是达到一定条件额外创建的,并且超过设置的存活时间会被销毁来回收系统资源。

线程池执行流程
  • 先判断核心线程是否满了,如果没满就创建核心线程执行任务
  • 如果核心线程满了,判断最大线程是否满了,如果没满,就创建非核心线程执行任务
  • 判断非核心线程是否超过存活时间,如果超过,就销毁这个线程
  • 如果线程池中的使用的线程数达到最大线程数,新的任务就会进入等待队列
  • 如果等待队列满了和线程池都满了,则调用拒绝策略
线程池拒绝策略
AbortPolicy(默认策略):

抛出RejectedExecutionException异常,表示拒绝执行新任务。

CallerRunsPolicy:

将任务返回给调用线程执行,如果线程池已关闭,则丢弃任务。

DiscardPolicy:

默默丢弃无法处理的任务,不给予任何处理。

DiscardOldestPolicy:

丢弃任务队列中等待时间最久的任务,然后将新任务加入队列。

自定义拒绝策略

一般需要实现RejectedExecutionHandler接口。以下是一个自定义的拒绝策略示例:

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 自定义拒绝策略,例如记录日志或将任务加入队列等
        System.err.println("Task rejected. " + r.toString());
    }
}

然后可以在创建线程池时使用自定义拒绝策略:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(queueCapacity), new CustomRejectedExecutionHandler());
线程池常用方法
shutdown

shutdown() 方法会优雅地关闭线程池,等待已提交的任务执行完成(可以设置最长等待时间),不再接受新任务。

shutdownNow

shutdownNow() 会先改状态为STOP不接收新的任务,并尝试取消正在执行的任务,立即关闭线程池 并返回未执行的任务列表

CountDownLatch

CountDownLatch是一种倒计时锁,允许一个或多个线程等待其他线程执行完毕才运行

// 创建countDownLatch 数量为线程数
CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 1; i <= maxPage; i++) {
     executor.execute(() -> {
         try{
             // 开线程执行业务逻辑
             xxx
         }catch{
             
         } finally {
             // 执行完一个线程任务就在finally中进行减1
    		countDownLatch.countDown();
    	}
    });
}
// 等待所有子线程执行完毕前会一直阻塞
countDownLatch.await();
// 后续主线程任务
xxx
setDefaultUncaughtExceptionHandler

用于为所有新创建的线程设置默认的未捕获异常处理器

相关推荐
奈斯ing2 分钟前
【Oracle篇】掌握SQL Tuning Advisor优化工具:从工具使用到SQL优化的全方位指南(第六篇,总共七篇)
运维·数据库·sql·oracle
2401_857622662 分钟前
网上商城系统设计与Spring Boot框架
java·spring boot·后端
0x派大星3 分钟前
【Goland】——Gin 框架中间件详解:从基础到实战
开发语言·后端·中间件·golang·go·gin
最后一个bug8 分钟前
C函数如何返回参数lua使用
linux·c语言·开发语言·嵌入式硬件·lua
芋头莎莎12 分钟前
STM32设计井下瓦斯检测联网WIFI加Zigbee多路节点协调器传输
c语言·数据库·stm32·单片机·嵌入式硬件·物联网
雷神乐乐14 分钟前
ServletConfig、ServletContext、HttpServletRequest与HttpServletResponse常见API
java·服务器·前端·javaweb·tomcat8
憶巷14 分钟前
JSP是如何被执行的?
java·开发语言
小汤猿人类25 分钟前
Spring Data Redis使用方式
java·redis·spring
Crossoads29 分钟前
【汇编语言】更灵活的定位内存地址的方法(二)—— 从 [bx+idata] 到 [bx+si+idata]:让你灵活的访问内存
android·java·服务器·网络协议·tcp/ip·机器学习·汇编语言
是桃萌萌鸭~35 分钟前
如何设置MySQL 数据库的默认字符集和默认排序规则
数据库·mysql