What is a thread pool
A thread pool is a collection of threads that [loop execution] multiple application logic in one or more threads.
Generally speaking, thread pools have the following parts:
One or more threads that complete the main task.
Management threads used for scheduling management.
The task queue required to be executed.
The function of thread pool:
The function of a thread pool is to limit the number of threads executed in the system.
Depending on the system environment, the number of threads can be automatically or manually set to achieve the best operation effect; less system resources are wasted, and more system congestion is not high. Use a thread pool to control the number of threads, and other threads are waiting in line. After a task is executed, the first task is taken from the queue to start execution. If there is no waiting process in the queue, this resource of the thread pool is waiting. When a new task needs to be run, if there are waiting worker threads in the thread pool, it can start running; otherwise, it will enter the waiting queue.
Implement thread pool by yourself
Based on the above understanding of thread pool, we write our own simple thread pool:
Simple thread pool interface:
public interface ThreadPool<Job extends Runnable>{ //Execute a task (Job), this job must implement Runnable void execute(Job job); //Close the thread pool void shutdown(); //Increase the worker thread, that is, the thread used to execute the task void addWorkers(int num); //Reduce the worker thread void removeWorker(int num); //Get the number of tasks waiting to be executed void getJobSize();}The client can submit the job to the thread pool through the execute(Job) method for execution, and the client does not have to wait for the job to be executed at all. In addition to the execute(Job) method, the thread pool interface provides methods to increase/decrease worker threads and close thread pools. Each client submits a job that will enter a work queue and wait for the worker thread to process.
The default implementation of thread pool interface
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job>{ // Maximum number of threads for thread pool maintenance worker thread private static final int MAX_WORKER_NUMBERS = 10; // Default value of thread pool maintenance worker thread private static final int DEFAULT_WORKER_NUMBERS = 5; // Minimum number of thread pool maintenance worker thread private static final int MIN_WORKER_NUMBERS = 1; // Maintain a work list, which adds the client-initiated work private final LinkedList<Job> jobs = new LinkedList<Job>(); // List of worker threads private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>()); // Number of worker threads private int workerNum; // Generate private AtomicLong threadNum = new AtomicLong(); // Generate thread pool public DefaultThreadPool() { this.workerNum = DEFAULT_WORKER_NUMBERS; initializeWorkers(this.workerNum); } public DefaultThreadPool(int num) { if (num > MAX_WORKER_NUMBERS) { this.workerNum =DEFAULT_WORKER_NUMBERS; } else { this.workerNum = num; } initializeWorkers(this.workerNum); }//Initialize each worker thread private void initializeWorkers(int num) { for (int i = 0; i < num; i++) { Worker worker = new Worker(); //Add to the list of workers threads workers.add(worker); //Start the worker thread Thread thread = new Thread(worker); thread.start(); } } public void execute(Job job) { if (job != null) { // According to the thread's "wait/notify mechanism", we must lock jobs synchronized (jobs) { jobs.addLast(job); jobs.notify(); } } } //Close the thread pool that is to close each worker thread public void shutdown() { for (Worker w : workers) { w.shutdown(); } } } //Add worker thread public void addWorkers(int num) { //Add lock to prevent the thread from increasing or completing while the next thread continues to increase, causing the worker thread to exceed the maximum value synchronized (jobs) { if (num + this.workerNum > MAX_WORKER_NUMBERS) { num = MAX_WORKER_NUMBERS - this.workerNum; } initializeWorkers(num); this.workerNum += num; } } //Reduce worker thread public void removeWorker(int num) { synchronized (jobs) { if(num>=this.workerNum){ throw new IllegalArgumentException("Exceed the number of existing threads"); } for (int i = 0; i < num; i++) { Worker worker = workers.get(i); if (worker != null) { // Close the thread and remove worker.shutdown(); workers.remove(i); } } this.workerNum -= num; } } public int getJobSize() { // TODO Auto-generated method stub return workers.size(); }// Define the worker thread class Worker implements Runnable { // Indicates whether the worker private volatile boolean running = true; public void run() { while (running) { Job job = null; //Thread wait/notification mechanism synchronized (jobs) { if (jobs.isEmpty()) { try { jobs.wait();//Thread waits for wakeup} catch (InterruptedException e) { //Senses the external interrupt operation on the thread, and returns Thread.currentThread().interrupt(); return; } } // Take out a job job = jobs.removeFirst(); } //Execute job if (job != null) { job.run(); } } } // Terminate the thread public void shutdown() { running = false; } }}
From the implementation of the thread pool, it can be seen that when the client calls the execute(Job) method, it will constantly add jobs to the task list jobs, and each worker thread will not read the jobs from the jobs to execute. When the jobs are empty, the worker thread enters the WAITING state.
After adding a job, the notify() method is called on the work queue jobs to wake up a worker thread. Here we do not call notifyAll() to avoid wasting resources by moving all threads in the waiting queue to the blocking queue.
The essence of a thread pool is to use a thread-safe work queue to connect worker threads and client threads. The client thread returns after putting the task into the work queue, while the worker thread mishandledly takes the work from the work queue and executes it. When the work queue is empty, the worker thread enters the WAITING state. When a client sends a task, it will pass through any worker thread. With the submission of a large number of tasks, more worker threads are awakened.
Reference: "The Art of Concurrent Programming in Java" Fang Tengfei