Java 中的线程池是一种高效地管理线程的方式,可以避免线程过多导致系统资源的浪费和线程频繁创建和销毁带来的性能问题。在本文中,我们将会介绍如何自己实现一个简单的线程池,以及如何在其中添加任务,附带相应的代码示例。
线程池的原理
在 Java 中,线程池是一种管理线程的机制,它可以创建一组线程并重复使用它们,避免了创建和销毁线程的开销。线程池中的线程可以执行提交的任务,当任务完成后就会返回到线程池中等待下一个任务的到来。线程池中通常包含一个线程池管理器、工作线程、任务队列和任务接口等组件。
线程池的核心思想是将线程的创建、销毁和管理等操作交给线程池来完成,从而避免了频繁地创建和销毁线程,节约了系统资源,提高了程序的效率。
线程池的实现
下面我们将介绍如何自己实现一个简单的线程池。
2.1. 实现一个任务队列
首先,我们需要实现一个任务队列来存储待执行的任务。任务队列可以是一个阻塞队列或者一个非阻塞队列。在本文中,我们将使用一个阻塞队列来作为任务队列。
public class TaskQueue {
private BlockingQueue<Runnable> queue;
public TaskQueue(int size) {
queue = new ArrayBlockingQueue<>(size);
}
public void addTask(Runnable task) {
queue.offer(task);
}
public Runnable getTask() throws InterruptedException {
return queue.take();
}
}
在上面的代码中,我们使用了一个 ArrayBlockingQueue 来作为任务队列,它是一个基于数组的有界阻塞队列,可以设置队列的大小,防止队列过大导致内存溢出。
2.2. 实现一个线程池管理器
接下来,我们需要实现一个线程池管理器来管理线程池的创建、销毁和任务的执行等操作。
public class ThreadPool {
private int size;
private TaskQueue taskQueue;
private List<WorkerThread> workerThreads;
public ThreadPool(int size, int taskQueueSize) {
this.size = size;
taskQueue = new TaskQueue(taskQueueSize);
workerThreads = new ArrayList<>();
for (int i = 0; i < size; i++) {
WorkerThread workerThread = new WorkerThread();
workerThread.start();
workerThreads.add(workerThread);
}
}
public void execute(Runnable task) throws InterruptedException {
taskQueue.addTask(task);
}
public void shutdown() {
for (WorkerThread workerThread : workerThreads) {
workerThread.stopThread();
}
}
private class WorkerThread extends Thread {
private volatile boolean isRunning = true;
@Override
public void run() {
while (isRunning) {
try {
Runnable task = taskQueue.getTask();
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopThread() {
isRunning = false;
}
}
}
在上面的代码中,我们使用了一个 TaskQueue 来存储待执行的任务,并使用一个 List 来存储工作线程。在线程池的构造函数中,我们创建了指定数量的工作线程,并将它们添加到 workerThreads 中。在 execute 方法中,我们将任务添加到任务队列中。在 shutdown 方法中,我们遍历 workerThreads 中的所有工作线程,将它们的 isRunning 标志设置为 false,从而停止工作线程的运行。
在 WorkerThread 中,我们使用一个 while 循环来不断地从任务队列中获取任务并执行。当 isRunning 标志为 false 时,线程就会停止运行。
线程池的使用
下面我们将演示如何使用我们刚刚实现的线程池。
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadPool threadPool = new ThreadPool(2, 10);
for (int i = 0; i < 20; i++) {
final int index = i;
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + ": " + index);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
Thread.sleep(5000);
threadPool.shutdown();
}
}
在上面的代码中,我们创建了一个 ThreadPool 对象,并使用 execute 方法向线程池中添加任务。在任务中,我们打印当前线程的名称和任务的索引,并让线程休眠 1 秒钟。在主线程中,我们让程序休眠 5 秒钟,并调用 shutdown 方法来停止线程池中的所有工作线程。
总结
本文介绍了如何自己实现一个简单的线程池。线程池的实现原理是将线程的创建、销毁和管理等操作交给线程池来完成,从而避免了频繁地创建和销毁线程,节约了系统资源,提高了程序的效率。线程池的实现包括一个任务队列和一个线程池管理器,可以通过 execute 方法向线程池中添加任务,并可以通过 shutdown 方法来停止线程池中的所有工作线程。