手写实现简易版线程池
首先封装自己的Task任务类
package com.im.socket.cdn.xiaoke;
import cn.hutool.cron.task.Task;
/**
* @Author: 无敌代码写手
* @CreateTime: 2025年09月09日
*/
public class ChxTask implements Task {
private String id;
private Task task;
public ChxTask(String id,Task task){
this.id = id;
this.task = task;
}
@Override
public void execute() {
this.task.execute();
}
public String getId() {
return this.id;
}
}
这里我封装了一个Task,实现Task接口,然后新增id字段,这样我们可以看到每个被处理的任务ID。
然后封装一下Thread类
package com.im.socket.cdn.xiaoke;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class ChxThread implements Runnable {
private final LinkedBlockingQueue<ChxTask> taskQueue;
private final boolean isCore;
private final long keepAliveMillis;
private final ChxThreadPool pool;
public ChxThread(LinkedBlockingQueue<ChxTask> taskQueue, boolean isCore, long keepAliveMillis, ChxThreadPool pool) {
this.taskQueue = taskQueue;
this.isCore = isCore;
this.keepAliveMillis = keepAliveMillis;
this.pool = pool;
}
@Override
public void run() {
try {
while (true) {
if (Thread.currentThread().isInterrupted()) break;
ChxTask task;
if (isCore) { // 如果是核心线程
task = taskQueue.take(); // 核心线程永远阻塞
} else {
// 如果非核心线程,等待最大超时时间
task = taskQueue.poll(keepAliveMillis, TimeUnit.MILLISECONDS);
if (task == null) {
System.out.println(Thread.currentThread().getName() + " 超时空闲,自动销毁");
break; // 非核心线程空闲超时退出
}
}
if (task != null) {
System.out.println(Thread.currentThread().getName() + " 执行任务ID:" + task.getId());
task.execute();
}
}
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 被中断退出");
} finally {
pool.removeThread(Thread.currentThread()); // 移除线程
}
}
}
这里仿照JDK官方的ThreadPool进行设计,封装的参数有:
- taskQueue:任务队列
- isCroe:是否为核心线程
- keepAliveMillis:最大等待时间
- pool:线程池
关键代码:
task = taskQueue.poll(keepAliveMillis, TimeUnit.MILLISECONDS);
if (task == null) {
System.out.println(Thread.currentThread().getName() + " 超时空闲,自动销毁");
break; // 非核心线程空闲超时退出
}
这一段代码是用来非核心线程是否应该自动 销毁的,如果是非核心线程,并且任务队列 为空,队列会等待最大超时时间,如果等待超时还没有任务进入队列就会返回空,那么该非核心线程就可以被销毁。
接下来是封装的线程池类ChxThreadPool:
package com.im.socket.cdn.xiaoke;
import cn.hutool.cron.task.Task;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* 自定义线程池
*/
public class ChxThreadPool {
private final int coreSize;
private final int maxSize;
private final int queueSize;
private final long keepAliveMillis;
private final List<Thread> threads;
private final LinkedBlockingQueue<ChxTask> queue;
private volatile boolean running = true;
public ChxThreadPool(int coreSize, int maxSize, int queueSize, long keepAliveMillis) {
this.coreSize = coreSize;
this.maxSize = maxSize;
this.queueSize = queueSize;
this.keepAliveMillis = keepAliveMillis;
this.queue = new LinkedBlockingQueue<>(queueSize);
this.threads = new ArrayList<>(maxSize);
// 启动核心线程
for (int i = 0; i < this.coreSize; i++) {
Thread thread = new Thread(new ChxThread(queue, true, keepAliveMillis, this));
thread.start();
threads.add(thread);
}
}
public synchronized void execute(Task task) {
if (!running) {
throw new RuntimeException("线程池已关闭,无法提交任务");
}
if (!queue.offer(new ChxTask(IdWorker.getIdStr(), task))) { // 队列满了
if (threads.size() < maxSize) { // 可以扩容
Thread t = new Thread(new ChxThread(queue, false, keepAliveMillis, this));
t.start();
threads.add(t);
System.out.println("扩容线程:" + t.getName() + "已加入线程池");
try {
queue.put(new ChxTask(IdWorker.getIdStr(), task)); // 阻塞直到有空位
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("任务提交被中断", e);
}
} else { // 队列满且线程池满
throw new RuntimeException("队列与线程池已满,拒绝任务");
}
}
}
/**
* 从线程池集合中移除已退出线程
*/
protected synchronized void removeThread(Thread t) {
threads.remove(t);
System.out.println(t.getName() + " 已从线程池移除");
}
/**
* 优雅关闭线程池
*/
public void shutdown() {
running = false;
synchronized (threads) {
for (Thread t : threads) {
t.interrupt();
}
}
}
public int getActiveThreadCount() {
return threads.size();
}
public int getQueueSize() {
return queue.size();
}
}
构造方法:
- coreSize:核心线程个数
- maxSize:最大支持多少线程数
- queueSize:任务队列容量
- keepAliveMillis:非核心线程空闲时最大存活时间
在构造方法中,根据核心线程数创建N个线程并存入threas线程集合中。
核心代码:
public synchronized void execute(Task task) {
if (!running) {
throw new RuntimeException("线程池已关闭,无法提交任务");
}
if (!queue.offer(new ChxTask(IdWorker.getIdStr(), task))) { // 队列满了
if (threads.size() < maxSize) { // 可以扩容
Thread t = new Thread(new ChxThread(queue, false, keepAliveMillis, this));
t.start();
threads.add(t);
System.out.println("扩容线程:" + t.getName() + "已加入线程池");
try {
queue.put(new ChxTask(IdWorker.getIdStr(), task)); // 阻塞直到有空位
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("任务提交被中断", e);
}
} else { // 队列满且线程池满
throw new RuntimeException("队列与线程池已满,拒绝任务");
}
}
}
该方法是线程池执行任务的方法,当用户扔进来一个任务,会尝试将他放进任务队列中,如果队列满了,会开启新线程进行处理。如果任务队列和最大线程都到满了,则会抛出异常(这里大家可以优化,我这个地方是为了看的更直观一些,抛出了异常)。
线程池运行流程:
- 有任务进来,使用核心线程处理
- 核心线程忙碌,先将任务放入任务队列
- 任务队列满了,开启非核心线程
- 非核心线程满了,拒绝任务
当时我想过修改流程的,我想核心线程忙碌直接开启非核心线程,然后非核心线程满了在存入任务队列,流程如下:
- 有任务进来,使用核心线程处理
- 核心线程忙碌,开启非核心线程处理
- 非核心线程满了,存入任务队列
- 任务队列程满了,拒绝任务
该操作在处理的方面虽然是快了不少,但是会早成性能开销比较严重。有更好想法的小伙伴可以评论交流。
最终使用:
package com.im.socket.cdn.xiaoke;
/**
* @Author: 无敌代码写手
* @CreateTime: 2025年09月09日
*/
public class ThreadDemo {
public static void main(String[] args) {
ChxThreadPool chxThreadPool = new ChxThreadPool(20, 50, 100,5000L);
for (int i = 0; i < 180; i++) {
int finalI = i;
chxThreadPool.execute(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("你好"+ finalI);
});
}
}
}


1716

被折叠的 条评论
为什么被折叠?



