Java | Implementation of thread pool based on Java

There are generally two ways to create a thread pool in java:

1. Created by Executors factory method
2. Created by new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)custom

One, Executors factory method creation

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class TestThreadPoolExecutor {
    
    
    public static void main(String[] args) {
    
    
        //创建使用单个线程的线程池
        ExecutorService es1 = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
    
    
            es1.submit(() -> System.out.println(Thread.currentThread().getName() + "正在执行任务"));
        }
        //创建使用固定线程数的线程池
        ExecutorService es2 = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
    
    
            es2.submit(() -> System.out.println(Thread.currentThread().getName() + "正在执行任务"));
        }
        //创建一个会根据需要创建新线程的线程池
        ExecutorService es3 = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {
    
    
            es3.submit(() -> System.out.println(Thread.currentThread().getName() + "正在执行任务"));
        }
        //创建拥有固定线程数量的定时线程任务的线程池
        ScheduledExecutorService es4 = Executors.newScheduledThreadPool(2);
        System.out.println("时间:" + System.currentTimeMillis());
        for (int i = 0; i < 5; i++) {
    
    
            es4.schedule(() -> System.out.println("时间:" + System.currentTimeMillis() + "--" + Thread.currentThread().getName() + "正在执行任务"), 3, TimeUnit.SECONDS);
        }
        //创建只有一个线程的定时线程任务的线程池
        ScheduledExecutorService es5 = Executors.newSingleThreadScheduledExecutor();
        System.out.println("时间:" + System.currentTimeMillis());
        for (int i = 0; i < 5; i++) {
    
    
            es5.schedule(() -> System.out.println("时间:" + System.currentTimeMillis() + "--" + Thread.currentThread().getName() + "正在执行任务"), 3, TimeUnit.SECONDS);
        }
    }
}

Two, new ThreadPoolExecutor() custom creation

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) ;

corePoolSize: The size of the core pool, this parameter has a very large relationship with the implementation principle of the thread pool described later. After the thread pool is created, by default, there is no thread in the thread pool. Instead, it waits for tasks to arrive before creating threads to perform tasks. Unless the prestartAllCoreThreads()or prestartCoreThread()method is called , you can see from the names of these two methods. It means to pre-create threads, that is, create corePoolSize threads or one thread before no tasks arrive. By default, after the thread pool is created, the number of threads in the thread pool is 0. When a task comes, a thread will be created to execute the task. When the number of threads in the thread pool reaches corePoolSize, it will reach Put the tasks in the cache queue;: the
maximumPoolSizemaximum number of threads in the thread pool, this parameter is also a very important parameter, it indicates the maximum number of threads that can be created in the thread pool;:
keepAliveTimeindicates how long the thread will be terminated when there is no task execution . By default corePoolSize, it keepAliveTimewill only work when the number of threads in the thread pool is greater than that, until the number of threads in the thread pool is not greater than corePoolSize, that is, when the number of threads in the thread pool is greater than corePoolSize, if the idle time of a thread reaches keepAliveTime, then Will terminate until the number of threads in the thread pool does not exceed corePoolSize. But if the allowCoreThreadTimeOut(boolean)method is called , when the number of threads in the thread pool is not greater than corePoolSize, the keepAliveTimeparameter will also work until the number of threads in the thread pool is 0
unit;: keepAliveTimethe time unit of the parameter , there are 7 values, TimeUnitthere are 7 in the class Kind of static properties:

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

workQueue: A blocking queue is used to store tasks waiting to be executed. The choice of this parameter is also very important and will have a significant impact on the running process of the thread pool. Generally speaking, there are several options for the blocking queue here:

ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
PriorityBlockingQueue

ArrayBlockingQueueAnd PriorityBlockingQueueuse less, generally use LinkedBlockingQueueand SynchronousQueue. The queuing strategy of the thread pool is BlockingQueuerelated.
threadFactory: Used to set the factory for creating threads. You can do more meaningful things for each created thread through the thread factory, such as setting the daemon and priority, etc
handler.: indicates the strategy when the task is rejected, there are the following four Value:

1、AbortPolicy:直接抛出异常。
2、CallerRunsPolicy:只用调用者所在线程来运行任务。
3、DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
4、DiscardPolicy:不处理,丢弃掉。
5、也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadTest {
    
    
    public static void main(String[] args) throws IOException {
    
    
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 10;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        ThreadFactory threadFactory = new NameTreadFactory();
        RejectedExecutionHandler handler = new MyIgnorePolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                workQueue, threadFactory, handler);
        executor.prestartAllCoreThreads(); // 预启动所有核心线程

        for (int i = 1; i <= 10; i++) {
    
    
            MyTask task = new MyTask(String.valueOf(i));
            executor.execute(task);
        }

        System.in.read(); //阻塞主线程
    }

    static class NameTreadFactory implements ThreadFactory {
    
    

        private final AtomicInteger mThreadNum = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
    
    
            Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
            System.out.println(t.getName() + " has been created");
            return t;
        }
    }

    public static class MyIgnorePolicy implements RejectedExecutionHandler {
    
    

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    
    
            doLog(r, e);
        }

        private void doLog(Runnable r, ThreadPoolExecutor e) {
    
    
            // 可做日志记录等
            System.err.println(r.toString() + " rejected");
//          System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
        }
    }

    static class MyTask implements Runnable {
    
    
        private String name;

        public MyTask(String name) {
    
    
            this.name = name;
        }

        @Override
        public void run() {
    
    
            try {
    
    
                System.out.println(this.toString() + " is running!");
                Thread.sleep(3000); //让任务执行慢点
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }

        public String getName() {
    
    
            return name;
        }

        @Override
        public String toString() {
    
    
            return "MyTask [name=" + name + "]";
        }
    }
}

Among them, thread threads 1-4 first fill up the core threads and the maximum number of threads, then threads 4 and 5 enter the waiting queue, threads 7-10 are directly ignored and refused to execute, and 4 and 5 are notified after threads 1-4 are executed. The thread continues execution.

Guess you like

Origin blog.csdn.net/y1534414425/article/details/108573631