实现线程池,一共有5个线程,线程池最大容量为3
此时线程池为定长线程池,只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列,可控制线程并发数。
package org.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 定义一个实现 Runnable 接口的任务类
class MyTask implements Runnable {
private final int taskId;
public MyTask(int taskId) {
this.taskId = taskId;
}
@Override
public void run() {
System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
try {
// 模拟任务执行耗时
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskId + " is completed.");
}
public static void main(String[] args) {
// 创建一个固定大小为 3 的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 提交 5 个任务给线程池
for (int i = 1; i <= 5; i++) {
executorService.submit(new MyTask(i));
}
// 关闭线程池
executorService.shutdown();
}
}
定时线程池
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
Runnable task =new Runnable(){
public void run() {
System.out.println("执行任务啦");
}
};
executorService.scheduleAtFixedRate(task,10,1000, TimeUnit.MILLISECONDS);// 延迟10ms后、每隔1000ms执行任务
可缓存线程池
// 1. 创建可缓存线程池对象
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task =new Runnable(){
public void run() {
System.out.println("执行任务啦");
}
};
// 3. 向线程池提交任务
cachedThreadPool.execute(task);
单任务线程池
// 1. 创建单线程化线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task =new Runnable(){
public void run() {
System.out.println("执行任务啦");
}
};
// 3. 向线程池提交任务
singleThreadExecutor.execute(task);
还可以通过 ThreadPoolExecutor
类来自定义线程池
package org.example;
import java.util.concurrent.*;
// 定义一个实现 Runnable 接口的任务类
class CustomTask implements Runnable {
private final int taskId;
public CustomTask(int taskId) {
this.taskId = taskId;
}
@Override
public void run() {
System.out.println("Custom Task " + taskId + " is running on thread " + Thread.currentThread().getName());
try {
// 模拟任务执行耗时
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Custom Task " + taskId + " is completed.");
}
public static void main(String[] args) {
// 自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
5, // 最大线程数
60, // 线程空闲时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(10) // 任务队列
);
// 提交 15 个任务给线程池
for (int i = 1; i <= 15; i++) {
executor.submit(new CustomTask(i));
}
// 关闭线程池
executor.shutdown();
}
}
核心线程数(Core Pool Size)
概念
核心线程数是线程池的基本配置之一,它表示线程池在正常情况下会一直保持存活的线程数量。当有新的任务提交到线程池时,线程池会优先使用核心线程来执行任务,即使这些核心线程当前处于空闲状态。
工作机制
-
当提交的任务数量小于等于核心线程数时,线程池会创建新的线程(直到达到核心线程数)来执行这些任务。这些核心线程会一直在线程池中存活,除非通过设置
allowCoreThreadTimeOut
为true
并指定了超时时间,使得核心线程在空闲一段时间后也会被销毁。 - 例如,若线程池的核心线程数设置为 3,当有 2 个任务提交时,线程池会创建 2 个线程来执行这 2 个任务,并且这 2 个线程会一直保留在线程池中等待新任务。
最大线程数(Maximum Pool Size)
概念
最大线程数是线程池允许创建的最大线程数量。当线程池中的核心线程都在执行任务,并且任务队列已满时,线程池会创建新的线程来处理新提交的任务,直到线程数量达到最大线程数。
工作机制
-
当提交的任务数量超过核心线程数,且任务队列已满时,线程池会尝试创建新的线程,直到线程数量达到最大线程数。如果此时还有新任务提交,会根据线程池的拒绝策略进行处理。
-
例如,线程池的核心线程数为 3,最大线程数为 5,任务队列容量为 2。当有 6 个任务提交时,3 个核心线程会先执行 3 个任务,另外 2 个任务会被放入任务队列,第 6 个任务由于队列已满,会创建一个新线程(此时线程总数达到 4)来执行该任务。
如果核心线程数大于最大线程数会报错
拒绝策略执行:当线程数量达到最大线程数且队列已满时,新提交的任务会触发线程池的拒绝策略。线程池任务队列设置过小会报错,原因默认拒绝策略会触发异常。
改变拒绝策略
AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。
CallerRunsPolicy:由调用线程处理该任务。
DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
5, // 最大线程数
60, // 线程空闲时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(2), // 任务队列
new ThreadPoolExecutor.DiscardPolicy()
);