Take you to write a Java thread pool freehand in 10 minutes

This article is shared from HUAWEI CLOUD community " [High Concurrency] Zoom in, Binghe will take you 10 minutes to play with the Java thread pool, yyds, hurry up and collect it ", author: Binghe.

The core principle of Java thread pool

Friends who have read the Java thread pool source code know that the core class in the Java thread pool is ThreadPoolExecutor, and the core construction method in the ThreadPoolExecutor class is the construction method with 7 parameters, as shown below.

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
复制代码

The meaning of each parameter is as follows.

  • corePoolSize: The number of resident core threads in the thread pool.
  • maximumPoolSize: The thread pool can accommodate the maximum number of threads executed at the same time, and this value is greater than or equal to 1.
  • keepAliveTime: The survival time of redundant idle threads. When the space time reaches the value of keepAliveTime, the redundant threads will be destroyed until only corePoolSize threads are left.
  • unit: unit of keepAliveTime.
  • workQueue: Task queue, tasks that have been submitted but not yet executed.
  • threadFactory: Indicates the thread factory that generates worker threads in the thread pool. Users create new threads, and generally use the default.
  • handler: Rejection strategy, indicating how to reject the runnable strategy for request execution when the thread queue is full and the worker thread is greater than or equal to the maximum display number (maxnumPoolSize) of the thread pool.

And Java's thread pool is implemented through the producer-consumer model. The user of the thread pool is the producer, and the thread pool itself is the consumer.

The core workflow of the Java thread pool is shown in the figure below.

Manual Java thread pool

The thread pool we manually implement is much simpler than Java's own thread pool. We have removed various complicated processing methods and only retained the core principle: users of the thread pool add tasks to the task queue, and threads The pool itself consumes tasks from the task queue and executes them.

只要理解了这个核心原理,接下来的代码就简单多了。在实现这个简单的线程池时,我们可以将整个实现过程进行拆解。拆解后的实现流程为:定义核心字段、创建内部类WorkThread、创建ThreadPool类的构造方法和创建执行任务的方法。

定义核心字段

首先,我们创建一个名称为ThreadPool的Java类,并在这个类中定义如下核心字段。

  • DEFAULT_WORKQUEUE_SIZE:静态常量,表示默认的阻塞队列大小。
  • workQueue:模拟实际的线程池使用阻塞队列来实现生产者-消费者模式。
  • workThreads:模拟实际的线程池使用List集合保存线程池内部的工作线程。

核心代码如下所示。

//默认阻塞队列大小
private static final int DEFAULT_WORKQUEUE_SIZE = 5;

//模拟实际的线程池使用阻塞队列来实现生产者-消费者模式
private BlockingQueue<Runnable> workQueue;

//模拟实际的线程池使用List集合保存线程池内部的工作线程
private List<WorkThread> workThreads = new ArrayList<WorkThread>();
复制代码

创建内部类WordThread

在ThreadPool类中创建一个内部类WorkThread,模拟线程池中的工作线程。主要的作用就是消费workQueue中的任务,并执行任务。由于工作线程需要不断从workQueue中获取任务,所以,这里使用了while(true)循环不断尝试消费队列中的任务。

核心代码如下所示。

//内部类WorkThread,模拟线程池中的工作线程
//主要的作用就是消费workQueue中的任务,并执行
//由于工作线程需要不断从workQueue中获取任务,使用了while(true)循环不断尝试消费队列中的任务
class WorkThread extends Thread{
    @Override
    public void run() {
        //不断循环获取队列中的任务
        while (true){
            //当没有任务时,会阻塞
            try {
                Runnable workTask = workQueue.take();
                workTask.run();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
复制代码

创建ThreadPool类的构造方法

这里,我们为ThreadPool类创建两个构造方法,一个构造方法中传入线程池的容量大小和阻塞队列,另一个构造方法中只传入线程池的容量大小。

核心代码如下所示。

//在ThreadPool的构造方法中传入线程池的大小和阻塞队列
public ThreadPool(int poolSize, BlockingQueue<Runnable> workQueue){
    this.workQueue = workQueue;
    //创建poolSize个工作线程并将其加入到workThreads集合中
    IntStream.range(0, poolSize).forEach((i) -> {
        WorkThread workThread = new WorkThread();
        workThread.start();
        workThreads.add(workThread);
    });
}

//在ThreadPool的构造方法中传入线程池的大小
public ThreadPool(int poolSize){
    this(poolSize, new LinkedBlockingQueue<>(DEFAULT_WORKQUEUE_SIZE));
}
复制代码

创建执行任务的方法

在ThreadPool类中创建执行任务的方法execute(),execute()方法的实现比较简单,就是将方法接收到的Runnable任务加入到workQueue队列中。

核心代码如下所示。

//通过线程池执行任务
public void execute(Runnable task){
    try {
        workQueue.put(task);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
复制代码

完整源码

这里,我们给出手动实现的ThreadPool线程池的完整源代码,如下所示。

package io.binghe.thread.pool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.IntStream;

/**
 * @author binghe
 * @version 1.0.0
 * @description 自定义线程池
 */
public class ThreadPool {

    //默认阻塞队列大小
    private static final int DEFAULT_WORKQUEUE_SIZE = 5;

    //模拟实际的线程池使用阻塞队列来实现生产者-消费者模式
    private BlockingQueue<Runnable> workQueue;

    //模拟实际的线程池使用List集合保存线程池内部的工作线程
    private List<WorkThread> workThreads = new ArrayList<WorkThread>();

    //在ThreadPool的构造方法中传入线程池的大小和阻塞队列
    public ThreadPool(int poolSize, BlockingQueue<Runnable> workQueue){
        this.workQueue = workQueue;
        //创建poolSize个工作线程并将其加入到workThreads集合中
        IntStream.range(0, poolSize).forEach((i) -> {
            WorkThread workThread = new WorkThread();
            workThread.start();
            workThreads.add(workThread);
        });
    }

    //在ThreadPool的构造方法中传入线程池的大小
    public ThreadPool(int poolSize){
        this(poolSize, new LinkedBlockingQueue<>(DEFAULT_WORKQUEUE_SIZE));
    }

 //通过线程池执行任务
    public void execute(Runnable task){
        try {
            workQueue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //内部类WorkThread,模拟线程池中的工作线程
    //主要的作用就是消费workQueue中的任务,并执行
    //由于工作线程需要不断从workQueue中获取任务,使用了while(true)循环不断尝试消费队列中的任务
    class WorkThread extends Thread{
        @Override
        public void run() {
            //不断循环获取队列中的任务
            while (true){
                //当没有任务时,会阻塞
                try {
                    Runnable workTask = workQueue.take();
                    workTask.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
复制代码

没错,我们仅仅用了几十行Java代码就实现了一个极简版的Java线程池,没错,这个极简版的Java线程池的代码却体现了Java线程池的核心原理。

接下来,我们测试下这个极简版的Java线程池。

编写测试程序

The test program is also relatively simple, that is, by calling the constructor of the ThreadPool class in the main() method, passing in the size of the thread pool, creating an instance of the ThreadPool class, and then calling the execute() method of the ThreadPool class 10 times in a loop to send data to the thread The tasks submitted in the pool are: 打印当前线程的名称--->> Hello ThreadPool.

The overall test code is as follows.

package io.binghe.thread.pool.test;

import io.binghe.thread.pool.ThreadPool;

import java.util.stream.IntStream;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试自定义线程池
 */
public class ThreadPoolTest {

    public static void main(String[] args){
        ThreadPool threadPool = new ThreadPool(10);
        IntStream.range(0, 10).forEach((i) -> {
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "--->> Hello ThreadPool");
            });
        });
    }
}
复制代码

Next, run the main() method of the ThreadPoolTest class, and the following information will be output.

Thread-0--->> Hello ThreadPool
Thread-9--->> Hello ThreadPool
Thread-5--->> Hello ThreadPool
Thread-8--->> Hello ThreadPool
Thread-4--->> Hello ThreadPool
Thread-1--->> Hello ThreadPool
Thread-2--->> Hello ThreadPool
Thread-5--->> Hello ThreadPool
Thread-9--->> Hello ThreadPool
Thread-0--->> Hello ThreadPool
复制代码

So far, our custom Java thread pool has been developed.

Summarize

The core principle of the thread pool is actually not complicated. As long as we analyze it patiently and understand the core essence of the thread pool in depth, you will find that the design of the thread pool is so elegant. I hope that this small example of a handwritten thread pool can give you a better understanding of the core principles of the thread pool.

Click to follow and learn about Huawei Cloud's fresh technologies for the first time~

Guess you like

Origin juejin.im/post/7229117001318170683