在很多场景下,创建线程并执行任务完,我们并不希望线程生命结束。因为重新创建线程的开销很大,如果能复用线程是最好不过得了。所以有了线程池就可以避免重复创建-销毁线程。
现在手写一个简单的线程池
思路
- 将执行的任务逻辑抽离,因此需要有一个任务队列
- 初始化时创建一定数量的线程,用来执行任务队列中的任务
- 当任务队列为空时,线程池中的线程等待唤醒,当有新任务加入时,唤醒线程
按照上述思路,先开始实现
首先定义好任务队列
private static final LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();
并且有一个添加任务的方法
public void addTask(Runnable runnable) {
synchronized (TASK_QUEUE) {
TASK_QUEUE.addLast(runnable);
TASK_QUEUE.notifyAll();
}
}
使用同步来保证线程安全,并且在添加完后notifyAll()
来唤醒线程池中的线程。
简单起见,可以将任务队列定义为一个先进先出的队列,因此取任务时,将第一个取出。
定义一个TaskExecutor
类,继承Thread,并且重写run方法,作为执行任务的线程。
为了标记被执行任务的状态,使用一个枚举类,分别表示任务的状态
enum TaskState {
FREE, RUNNING, BLOCKED, DEAD
}
重新run方法
public void run() {
OUTER:
while (taskState != TaskState.DEAD) {
Runnable runnable;
synchronized (TASK_QUEUE) {
while (TASK_QUEUE.isEmpty()) {
try {
taskState = TaskState.BLOCKED;
TASK_QUEUE.wait();
} catch (InterruptedException e) {
e.printStackTrace();
break OUTER;
}
}
runnable = TASK_QUEUE.removeFirst();
}
taskState = TaskState.RUNNING;
runnable.run();
taskState = TaskState.FREE;
}
}
如果任务队列为空,则wait
,否则获取队列中的Runnable
,并执行。使用TASK_QUEUE.removeFirst()
来获取第一个元素,保证先进先出。
完整代码
public class SimpleThreadPool {
private final int size;
private final static int DEFAULT_SIZE = 10;
private static final LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();
private static final String THREAD_PREFIX = "SIMPLE_THREAD_POOL-";
private static volatile int seq = 0;
private static final List<Thread> TASK_EXECUTORS = new ArrayList<>();
private static final ThreadGroup THREAD_GROUP = new ThreadGroup("Simple_Threadpool_group");
public SimpleThreadPool() {
this(DEFAULT_SIZE);
}
public SimpleThreadPool(int size) {
this.size = size;
init();
}
private void init() {
for (int i = 0; i < size; i++) {
TaskExecutor taskExecutor = createExecutor();
TASK_EXECUTORS.add(taskExecutor);
taskExecutor.start();
}
}
public void addTask(Runnable runnable) {
synchronized (TASK_QUEUE) {
TASK_QUEUE.addLast(runnable);
TASK_QUEUE.notifyAll();
}
}
private TaskExecutor createExecutor() {
TaskExecutor executor = new TaskExecutor(THREAD_GROUP, THREAD_PREFIX + (seq++));
return executor;
}
enum TaskState {
FREE, RUNNING, BLOCKED, DEAD
}
private class TaskExecutor extends Thread {
private TaskState taskState = TaskState.FREE;
private TaskExecutor(ThreadGroup threadGroup, String name) {
super(threadGroup, name);
}
public void run() {
OUTER:
while (taskState != TaskState.DEAD) {
Runnable runnable;
synchronized (TASK_QUEUE) {
while (TASK_QUEUE.isEmpty()) {
try {
taskState = TaskState.BLOCKED;
TASK_QUEUE.wait();
} catch (InterruptedException e) {
e.printStackTrace();
break OUTER;
}
}
runnable = TASK_QUEUE.removeFirst();
}
taskState = TaskState.RUNNING;
runnable.run();
taskState = TaskState.FREE;
}
}
public void shutdown() {
taskState = TaskState.DEAD;
}
}
}
测试
public class SimpleThreadPoolTest {
public static void main(String[] args) {
SimpleThreadPool pool = new SimpleThreadPool();
for (int i = 0; i < 40; i++) {
int finalI = i;
pool.addTask(() -> {
System.out.println(Thread.currentThread().getName() + " ==> is execute task " + finalI);
try {
Thread.sleep(2_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
新建线程池,默认线程10个。给它40个任务
运行结果
SIMPLE_THREAD_POOL-9 ==> is execute task 0
SIMPLE_THREAD_POOL-1 ==> is execute task 8
SIMPLE_THREAD_POOL-8 ==> is execute task 1
SIMPLE_THREAD_POOL-4 ==> is execute task 5
SIMPLE_THREAD_POOL-5 ==> is execute task 4
SIMPLE_THREAD_POOL-3 ==> is execute task 6
SIMPLE_THREAD_POOL-7 ==> is execute task 2
SIMPLE_THREAD_POOL-6 ==> is execute task 3
SIMPLE_THREAD_POOL-2 ==> is execute task 7
SIMPLE_THREAD_POOL-0 ==> is execute task 9
SIMPLE_THREAD_POOL-1 ==> is execute task 12
SIMPLE_THREAD_POOL-6 ==> is execute task 19
SIMPLE_THREAD_POOL-0 ==> is execute task 18
SIMPLE_THREAD_POOL-2 ==> is execute task 17
SIMPLE_THREAD_POOL-7 ==> is execute task 16
SIMPLE_THREAD_POOL-8 ==> is execute task 11
SIMPLE_THREAD_POOL-9 ==> is execute task 10
SIMPLE_THREAD_POOL-5 ==> is execute task 14
SIMPLE_THREAD_POOL-3 ==> is execute task 15
SIMPLE_THREAD_POOL-4 ==> is execute task 13
SIMPLE_THREAD_POOL-1 ==> is execute task 20
SIMPLE_THREAD_POOL-7 ==> is execute task 26
SIMPLE_THREAD_POOL-0 ==> is execute task 22
SIMPLE_THREAD_POOL-9 ==> is execute task 24
SIMPLE_THREAD_POOL-6 ==> is execute task 21
SIMPLE_THREAD_POOL-8 ==> is execute task 23
SIMPLE_THREAD_POOL-2 ==> is execute task 25
SIMPLE_THREAD_POOL-3 ==> is execute task 27
SIMPLE_THREAD_POOL-4 ==> is execute task 29
SIMPLE_THREAD_POOL-5 ==> is execute task 28
SIMPLE_THREAD_POOL-0 ==> is execute task 30
SIMPLE_THREAD_POOL-6 ==> is execute task 35
SIMPLE_THREAD_POOL-8 ==> is execute task 34
SIMPLE_THREAD_POOL-7 ==> is execute task 31
SIMPLE_THREAD_POOL-9 ==> is execute task 36
SIMPLE_THREAD_POOL-1 ==> is execute task 32
SIMPLE_THREAD_POOL-2 ==> is execute task 33
SIMPLE_THREAD_POOL-3 ==> is execute task 37
SIMPLE_THREAD_POOL-5 ==> is execute task 39
SIMPLE_THREAD_POOL-4 ==> is execute task 38
可以看到40个任务被SIMPLE_THREAD_POOL-0到SIMPLE_THREAD_POOL-9这10个线程执行了,一个简单的线程池就完成了