11.线程池
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用
线程池(英语:thread pool)一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度
特点:
降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的销耗。
提高响应速度: 当任务到达时,任务可以不需要等待线程创建就能立即执行。
提高线程的可管理性: 线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。具体架构:
Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor 这几个类
说明:Executors为工具类,I为接口类,C为实现类
1 种类与创建
Executors.newFixedThreadPool(int)一池N线程
ExecutorService threadPool1 = Executors.newFixedThreadPool(5); //5个窗口
Executors.newSingleThreadExecutor()一池一线程
ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); //一个窗口
Executors.newCachedThreadPool()一池可扩容根据需求创建线程
ExecutorService threadPool3 = Executors.newCachedThreadPool();
执行线程
execute()
关闭线程shutdown()
void execute(Runnable command);
参数为Runnable接口类,可以通过设置lambda
具体案例代码案例
//演示线程池三种常用分类
public class ThreadPoolDemo1 {
public static void main(String[] args) {
//一池五线程
ExecutorService threadPool1 = Executors.newFixedThreadPool(5); //5个窗口
//一池一线程
ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); //一个窗口
//一池可扩容线程
ExecutorService threadPool3 = Executors.newCachedThreadPool();
//10个顾客请求
try {
for (int i = 1; i <=10; i++) {
//执行
threadPool3.execute(()->{
System.out.println(Thread.currentThread().getName()+" 办理业务");
});
}
}catch (Exception e) {
e.printStackTrace();
}finally {
//关闭
threadPool3.shutdown();
}
}
}
2 底层原理
通过查看上面三种方式创建对象的类源代码
都有new ThreadPoolExecutor
具体查看该类的源代码,涉及七个参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
具体代码中的七个参数讲解:
int corePoolSize, 常驻线程数量(核心)
int maximumPoolSize,最大线程数量
long keepAliveTime,TimeUnit unit,线程存活时间
BlockingQueue<Runnable> workQueue,阻塞队列(排队的线程放入)
ThreadFactory threadFactory,线程工厂,用于创建线程
RejectedExecutionHandler handler拒绝测试(线程满了)
具体工作流程是:
在执行创建对象的时候不会创建线程
创建线程的时候execute()才会创建
先到常驻线程,满了之后再到阻塞队列进行等待,阻塞队列满了之后,在往外扩容线程,扩容线程不能大于最大线程数。大于最大线程数和阻塞队列之和后,会执行拒绝策略。
阻塞队列为3,常驻线程数2,最大线程数5
具体的拒绝策略有:
- 抛异常
- 谁调用找谁
- 抛弃最久执行当前
- 不理不问
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
2L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
其他都同理,只是调用ThreadPoolExecutor类,自定义参数
//自定义线程池创建 完整演示
public class ThreadPoolDemo2 {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
2L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
//10个顾客请求
try {
for (int i = 1; i <=10; i++) {
//执行
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" 办理业务");
});
}
}catch (Exception e) {
e.printStackTrace();
}finally {
//关闭
threadPool.shutdown();
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?