随笔记录
实现一个简单的线程池
2025-3-10 diaba


实现一个简单的线程池需要考虑以下几个关键点:




  1. 任务队列:用于存储待执行的任务。


  2. 工作线程:线程池中的线程,负责从任务队列中取出任务并执行。


  3. 任务提交:提供方法允许外部提交任务到线程池。


  4. 线程管理:控制线程的创建、销毁和复用。



以下是一个简单的线程池实现,支持任务的提交和执行:



import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class SimpleThreadPool {
// 线程池中的线程数量
private final int poolSize;
// 任务队列
private final Queue<Runnable> taskQueue = new LinkedList<>();
// 线程池中的工作线程
private final WorkerThread[] threads;
// 锁和条件变量
private final ReentrantLock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
// 线程池是否关闭
private volatile boolean isShutdown = false;

public SimpleThreadPool(int poolSize) {
this.poolSize = poolSize;
this.threads = new WorkerThread[poolSize];

// 创建并启动工作线程
for (int i = 0; i < poolSize; i++) {
threads[i] = new WorkerThread();
threads[i].start();
}
}

// 提交任务到线程池
public void submit(Runnable task) {
if (isShutdown) {
throw new IllegalStateException("Thread pool is shut down.");
}

lock.lock();
try {
taskQueue.add(task);
notEmpty.signal(); // 唤醒一个等待的工作线程
} finally {
lock.unlock();
}
}

// 关闭线程池
public void shutdown() {
lock.lock();
try {
isShutdown = true;
notEmpty.signalAll(); // 唤醒所有等待的工作线程
} finally {
lock.unlock();
}
}

// 工作线程类
private class WorkerThread extends Thread {
@Override
public void run() {
while (true) {
Runnable task = null;

lock.lock();
try {
// 检查线程池是否关闭
if (isShutdown && taskQueue.isEmpty()) {
return; // 如果线程池关闭且任务队列为空,则退出线程
}

// 如果任务队列为空,则等待
while (taskQueue.isEmpty() && !isShutdown) {
notEmpty.await();
}

// 如果线程池未关闭,则取出一个任务
if (!isShutdown) {
task = taskQueue.poll();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}

// 执行任务
if (task != null) {
task.run();
}
}
}
}
}



代码解析





  1. 任务队列




    • 使用LinkedList作为任务队列,存储待执行的任务。


    • 使用ReentrantLockCondition来实现线程安全的任务队列操作。





  2. 工作线程




    • 每个工作线程继承自Thread类,重写run方法。


    • 工作线程在运行时会不断从任务队列中取出任务并执行。


    • 如果任务队列为空,工作线程会调用notEmpty.await()进入等待状态,直到有任务被提交。





  3. 任务提交




    • 提供submit方法,允许外部提交任务到线程池。


    • 提交任务时,将任务添加到任务队列,并调用notEmpty.signal()唤醒一个等待的工作线程。





  4. 线程池关闭




    • 提供shutdown方法,关闭线程池。


    • 设置isShutdown标志为true,并调用notEmpty.signalAll()唤醒所有等待的工作线程。


    • 工作线程在检测到isShutdowntrue且任务队列为空时,退出运行。





使用示例



public class Main {
public static void main(String[] args) {
SimpleThreadPool threadPool = new SimpleThreadPool(4); // 创建一个包含4个工作线程的线程池

// 提交任务
for (int i = 0; i < 10; i++) {
int taskNumber = i;
threadPool.submit(() -> {
System.out.println("Executing task: " + taskNumber + " on thread: " + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟任务执行时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}

// 关闭线程池
threadPool.shutdown();
}
}





输出示例


Executing task: 0 on thread: WorkerThread-0
Executing task: 1 on thread: WorkerThread-1
Executing task: 2 on thread: WorkerThread-2
Executing task: 3 on thread: WorkerThread-3
Executing task: 4 on thread: WorkerThread-0
Executing task: 5 on thread: WorkerThread-1
Executing task: 6 on thread: WorkerThread-2
Executing task: 7 on thread: WorkerThread-3
Executing task: 8 on thread: WorkerThread-0
Executing task: 9 on thread: WorkerThread-1


注意事项




  1. 线程安全:使用ReentrantLockCondition确保任务队列操作的线程安全。


  2. 优雅关闭:在关闭线程池时,确保所有任务都被执行完毕,然后让工作线程安全退出。


  3. 异常处理:在实际应用中,需要对任务执行中的异常进行处理,避免一个任务的失败导致整个线程池停止工作。



这个简单的线程池实现可以作为学习和理解线程池工作原理的基础。在实际项目中,建议使用Java标准库中的java.util.concurrent包提供的线程池实现(如ExecutorService),它们经过了严格的测试和优化,功能更加完善。

发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容