线程池核心设计与实现
Java 中的线程池核心实现类是
ThreadPoolExecutor
,本文基于 JDK 1.8 的源码来分析 Java 线程池的核心设计与实现。
Executor
ThreadPoolExecutor
实现的顶层接口是Executor
。
Executor
提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供Runnable
对象,将任务的运行逻辑提交到执行器(Executor
)中,由Executor
框架完成线程的调配和任务的执行部分。
ExecutorService
ExecutorService
接口增加了一些能力:
- 扩展了可异步跟踪执行任务生成返回值
Future
的方法,如submit()
等方法。- 提供了管控线程池生命周期的方法,如
shutDown()
,shutDownNow()
等。
AbstractExecutorService
AbstractExecutorService
则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。最下层的实现类
ThreadPoolExecutor
实现最复杂的运行部分,ThreadPoolExecutor
将会一方面维护自身的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务。
ThreadPoolExecutor
线程池使用核心类
·corePool:核心线程池的大小。
·maximumPool:最大线程池的大小。
·BlockingQueue:用来暂时保存任务的工作队列。
·RejectedExecutionHandler:当ThreadPoolExecutor已经关闭或ThreadPoolExecutor已经饱和时(达到了最大线程池大小且工作队列已满),execute()方法将要调用的Handler
线程池接口继承实现类图,最终使用ThreadPoolExecutor类来使用JDK提供的线程池功能
线程池模拟处理生产者/消费者业务模型
/**
* TODO 模拟场景: 1000000个处理任务, 队列10000, 总计只有100个线程进行处理, 每个线程需要处理0.02秒, 模拟实现类似业务场景
*
* @author :seagull
* @date :Created in 2022/10/11
* @description:
* @modified By:
*/
public class ThreadTest {
public static ThreadPoolExecutor poolExecutor;
static {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10000);
poolExecutor = new ThreadPoolExecutor(1, 100, 5, TimeUnit.MINUTES, queue);
}
static class MyThread<T> extends Thread {
T obj;
public MyThread(T obj) {
this.obj = obj;
}
}
public static void main(String[] args) {
for (int i = 0; i < 1000000; i++) {
String completedMsg = "第" + (i + 1) + "个任务执行完成! ";
MyThread<String> thread = new MyThread<String>(completedMsg) {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
long threadId = Thread.currentThread().getId();
int size = poolExecutor.getQueue().size();
int activeCount = poolExecutor.getActiveCount();
System.out.printf("线程名:%s 线程id:%s 消息:%s 剩余:%s 活跃线程:%s\r\n", threadName, threadId, this.obj, size, activeCount);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
poolExecutor.execute(thread);
System.out.printf("第%s个任务已添加\r\n", i + 1);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("主线程结束.");
}
}
实际业务处理简单使用
/**
* @author :seagull
* @date :Created in 2022/10/11
* @description:
* @modified By:
*/
public class FileThreadPoolUtil {
static ThreadPoolExecutor poolExecutor;
static int addErrorCount = 0;
static class MyRejectPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (r instanceof FileDealThread) {
addErrorCount++;
FileDealThread dealThread = (FileDealThread) r;
System.out.println(addErrorCount + ":拒绝处理任务:数据:" + dealThread.task.errorMsg);
}
}
}
static {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(1000);
ThreadFactory factory = new CustomizableThreadFactory("file-deal-pool-");
poolExecutor = new ThreadPoolExecutor(3, 100, 5, TimeUnit.MINUTES, queue, factory, new MyRejectPolicy());
}
static class FileDealThread<T> extends Thread {
FileDealTask task;
public FileDealThread(FileDealTask task) {
this.task = task;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
long threadId = Thread.currentThread().getId();
int size = poolExecutor.getQueue().size();
int activeCount = poolExecutor.getActiveCount();
System.out.printf("线程名:%s 线程id:%s 剩余:%s 活跃线程:%s\r\n", threadName, threadId, size, activeCount);
task.run();
}
}
public static abstract class FileDealTask {
// 数据
protected String finalImgBase64;
// 存储文件
protected String finalTargetFilePath;
protected String fileName;
String errorMsg;
public abstract void run();
public FileDealTask(String finalImgBase64, String finalTargetFilePath, String fileName) {
this.finalImgBase64 = finalImgBase64;
this.finalTargetFilePath = finalTargetFilePath;
this.fileName = fileName;
this.errorMsg = (finalImgBase64 + ":" + finalTargetFilePath + ":" + fileName);
}
}
public static <T> void addTask(FileDealTask task) {
poolExecutor.execute(new FileDealThread<T>(task));
}
}
FileThreadPoolUtil.addTask(new FileThreadPoolUtil.FileDealTask("", filePathString, fileName) {
@Override
public void run() {
System.out.println("缓存文件路径:" + filePathString);
}
});
Executors
Executors类主要用于提供线程池相关的操作,它提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
Executors的几种线程池实现
5个,分别如下:
1.newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。(线程最大并发数不可控制)
2.newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
5.newWorkStealingPool:jdk1.8新增,创建持有足够线程的线程池来支持给定的并行级别,并通过使用多个队列,减少竞争,它需要穿一个并行级别的参数,如果不传,则被设定为默认的CPU数量。