欢迎浏览高耳机的博客
希望我们彼此都有更好的收获
感谢三连支持!
在当今软件开发领域,多线程编程已成为提升应用性能的核心技术。随着业务需求的增长,线程的频繁创建和销毁不仅增加了系统的开销,也影响了程序的运行效率。
尽管线程的生命周期管理比进程更为轻量,但在高频率操作下,其效率仍然有待提高。 为了应对这一挑战,线程池技术应运而生。线程池的核心思想是复用,它将不再忙碌的线程保存起来,而不是销毁。当新任务到来时,线程池会重用这些线程,避免了频繁地进行系统级创建和销毁操作。
通过这种方式,线程池实现了资源的高效利用。它不仅减少了创建线程的开销,还提高了程序的响应速度。线程池就像是提前准备好的资源库,让我们能够快速地分配线程来处理任务,从而在多线程环境中实现性能的最优化。
线程池的参数介绍
理解 ThreadPoolExecutor 构造方法的参数
把创建一个线程池想象成开个公司。每个员工相当于一个线程。
-
corePoolSize:正式员工的数量。(正式员工,一旦录用,永不辞退)
-
maximumPoolSize:正式员工 + 临时工的数量。(临时工:一段时间不干活,就被辞退)
-
keepAliveTime:临时工允许的空闲时间。
-
unit:keepAliveTime 的时间单位,是秒、分钟,还是其他值。
-
workQueue:传递任务的阻塞队列。
-
threadFactory:创建线程的工厂,参与具体的创建线程工作。
-
RejectedExecutionHandler:拒绝策略,如果任务量超出公司的负荷了,接下来怎么处理。
- AbortPolicy():超过负荷,直接抛出异常。
- CallerRunsPolicy():调用者负责处理。
- DiscardOldestPolicy():丢弃队列中最老的任务。
线程池的工作流程
线程池的工作流程大致如下:
-
任务提交:当一个任务被提交给线程池时,线程池会根据当前的线程数量和工作队列的状态来决定如何处理这个任务。
-
核心线程检查:如果当前运行的线程数量小于核心线程数,线程池会创建一个新的核心线程来执行任务。
-
工作队列:如果核心线程都在忙碌,新的任务会被放入工作队列中等待执行。
-
非核心线程检查:如果工作队列已满,且当前运行的线程数量小于最大线程数,线程池会创建一个新的非核心线程来执行任务。
-
拒绝策略:如果工作队列已满,且线程池中的线程数量已达到最大值,线程池会使用拒绝策略来处理新提交的任务。
-
任务执行:线程从工作队列中取出任务并执行。
-
线程复用:执行完任务的线程不会销毁,而是可以重复使用。
使用Executors创建常见的线程池
Java的java.util.concurrent
包提供了Executors
工厂类,用于创建不同类型的线程池:
newFixedThreadPool | 创建固定线程数的线程池 |
newCachedThreadPool | 创建线程数⽬动态增⻓的线程池 |
newSingleThreadExecutor | 创建只包含单个线程的线程池 |
newScheduledThreadPool | 设定延迟时间后执⾏命令,或者定期执⾏命令 |
Executors本质上是ThreadPoolExecutor类的封装.
//创建固定线程数的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo17 {
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(4);
for (int i = 0; i < 100; i++) {
int id = 1;
service.submit(() -> {
Thread current = Thread.currentThread();
System.out.println("hello thread " + id + "," + current.getName());
});
}
//不要立即终止,等待任务执行一段时间
Thread.sleep(2000);
//终止线程池的线程
service.shutdown();
System.out.println("程序退出");
}
}
//模拟实现线程池
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
class MyThreadPool {
private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
//此处n表示创建几个线程
public MyThreadPool(int n) {
for (int i = 0; i < n; i++) {
Thread t = new Thread(() -> {
//循环队列中读取任务,
while (true) {
try {
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
}
}
//添加任务
public void submit(Runnable runnable) {
try {
queue.put(runnable);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public class Demo15 {
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool(4);
for (int i = 0; i < 1000; i++) {
int id = i;
pool.submit(() -> {
System.out.println("执行任务" + id + "," + Thread.currentThread().getName());
});
}
}
}
线程池的核心优势
- 资源利用率高:线程池通过重用已有线程,减少了线程创建和销毁的频率,从而降低了系统开销。
- 响应速度快:线程池中的线程处于待命状态,可以迅速响应新任务,提高了程序的响应速度。
- 并发控制:线程池通过控制线程数量,防止过多的线程消耗系统资源,从而避免了系统过载。
- 任务管理方便:线程池提供了集中管理线程的机制,简化了多线程程序的复杂性。
结论
线程池是并发编程中的一项基本工具,它通过减少线程创建和销毁的开销,提高了程序的性能和稳定性。了解线程池的工作原理和参数配置,可以帮助我们更好地利用这一工具,编写出更高效、更健壮的多线程程序。在实际应用中,合理配置线程池参数,根据业务需求选择合适的线程池类型,是确保程序高效运行的关键。
希望这篇博客能为你理解线程池提供一些帮助。
如有不足之处请多多指出。
我是高耳机。