Java 线程池的种类、如何使用、运行原理
Java 线程池
一、线程池介绍
线程池就是提前创建若干的线程,如果有任务需要处理,池子里面的线程就会处理任务,处理完之后,并不会把该线程处理,也就是销毁。而是等待下一个任务的到来。创建和销毁线程是非常销毁系统的资源的,如果不想频繁的创建和销毁线程就需要考虑用线程池来处理相关事项。
二、线程池种类
在 Java 里面,创建线程池有两种方式。一种是通过 Executors 工厂类提供的方法,另外一种就是用 Executor 具体实现来自定义线程池。
2.1 通过 Executors 提供的方法
1、newCachedThreadPool
2、newFixedThreadPool
3、newScheduledThreadPool
4、newSingleThreadExecutor
2.2 Executor 实现类 ThreadPoolExecutor 自定义线程池
ThreadPoolExecutor类提供了4种构造方法,可根据具体需要来自定义一个线程池。
ThreadPoolExecutor 的构造函数如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize:核心线程池的大小(即使这些线程空闲也会一直存在,直到被 allowCoreThreadTimeOut 设置为 true)。
- maximumPoolSize:线程池允许的最大线程数。当队列已满且线程数小于最大值时,新的任务将会创建新的线程来执行。
- keepAliveTime:非核心线程空闲时的存活时间。
- unit:keepAliveTime 的时间单位(如 TimeUnit.SECONDS、TimeUnit.MILLISECONDS 等)
- workQueue:任务队列,任务会被提交到队列中等待线程来执行。常用的队列有 ArrayBlockingQueue、LinkedBlockingQueue 等。
- threadFactory:线程工厂,用于创建新线程。如果没有特殊需求,通常使用默认的 Executors.defaultThreadFactory()。
- handler:拒绝策略,当线程池中的线程都在工作且队列已满时,新的任务会被拒绝,拒绝策略定义了如何处理这种情况。
常用的拒绝策略(RejectedExecutionHandler)
AbortPolicy(默认策略):直接抛出异常(RejectedExecutionException)。
CallerRunsPolicy:让调用者线程自己执行任务。
DiscardPolicy:丢弃任务,不抛出异常。
DiscardOldestPolicy:丢弃队列中最旧的任务,尝试执行新任务。
线程池的创建和使用
我们可以根据实际需求来创建自定义的线程池,下面是一个常见的 ThreadPoolExecutor 配置和使用的例子
示例:自定义线程池
import java.util.concurrent.*;
public class CustomThreadPoolExecutor {
public static void main(String[] args) {
// 1. 定义线程池参数
int corePoolSize = 4; // 核心线程池大小
int maximumPoolSize = 8; // 最大线程池大小
long keepAliveTime = 60; // 线程空闲时的存活时间(秒)
TimeUnit unit = TimeUnit.SECONDS; // 时间单位
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10); // 队列大小为 10
ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 默认线程工厂
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 默认拒绝策略
// 2. 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
handler
);
// 3. 提交任务
for (int i = 0; i < 20; i++) {
final int taskId = i;
executor.submit(() -> {
try {
System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
// 模拟任务执行时间
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 4. 关闭线程池
executor.shutdown();
}
}
三、线程池的使用 (应用场景)
1、异步处理
2、批量数据处理
3、并行计算
四、线程池的工作原理
首先线程池的内部是通过线程+队列来实现的,当我们利用线程池执行任务时。
1、如果此时线程池里面的数量小于corePoolSize ,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
2、如果此时线程池中的线程数量等于 corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
3、如果此时线程池中的数量大于等于 corePoolSize ,缓冲队列 workQueue 满了,并且线程池中的数量少于 maximumPoolSIze,建新的线程来处理被添加的任务。
4、如果此时线程池中的线程数量大于 corePoolSize,缓冲队列 workQueue满,并且线程池中的数量等于 maximumPoolSize,那么通过 handler 所指定的策略来处理此任务。
5、当线程池中的线程数大于 corePoolSize 时,如果某线程空闲时间超过 keepAliveTime,线程将被总止,这样,线程池可以动态的调整池中的线程数量。
原文地址:https://blog.csdn.net/qq_44538738/article/details/122576166
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!