There are 7 ways to create thread pool. It is strongly recommended that you use it

According to Moore's law, the number of transistors that can be accommodated on the integrated circuit doubles every 18 months, so the number of transistors on the CPU will be more and more.

However, with the passage of time, the number of transistors that can be accommodated in integrated circuits has become saturated, and Moore's law has gradually failed. Therefore, multi-core CPU has gradually become the mainstream, and the corresponding multi-threaded programming has begun to become popular. Of course, it was a long time ago. For now, multi-threaded programming has become a necessary professional skill for programmers, Then let's talk about "thread pool", the most important topic in multithreaded programming.

What is a thread pool?

ThreadPool is a mechanism to manage and use threads based on the idea of pooling. It stores multiple threads in a "pool" in advance. When a task occurs, it can avoid the performance overhead caused by re creating and destroying threads. It only needs to take out the corresponding threads from the "pool" to execute the corresponding tasks.

The idea of pooling is also widely used in computers, such as the following:

The advantages of thread pool are mainly reflected in the following four points:

At the same time, Alibaba also stipulates in its java development manual that thread resources must be provided through the thread pool, and it is not allowed to create threads explicitly in the application.

After knowing what a thread pool is and why to use it, let's see how to use it.

Thread pool usage

There are seven methods to create thread pools, but generally speaking, they can be divided into two categories:

There are 7 ways to create a thread pool (6 of which are created through executors and 1 through ThreadPoolExecutor):

The meaning of single thread pool can be seen from the above code. Newsinglethreadexecutor and newsinglethreadscheduledexecutor create single thread pools. What is the meaning of single thread pool? A: although it is a single thread pool, it provides work queue, life cycle management, worker thread maintenance and other functions.

Next, let's look at the specific use of each thread pool creation.

1.FixedThreadPool

Create a thread pool with a fixed size to control the number of concurrent threads. Excess threads will wait in the queue.

Use examples are as follows:

public static void fixedThreadPool() {
    // 创建 2 个数据级的线程池
    ExecutorService threadPool = Executors.newFixedThreadPool(2);

    // 创建任务
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
        }
    };

    // 线程池执行任务(一次添加 4 个任务)
    // 执行任务的方法有两种:submit 和 execute
    threadPool.submit(runnable);  // 执行方式 1:submit
    threadPool.execute(runnable); // 执行方式 2:execute
    threadPool.execute(runnable);
    threadPool.execute(runnable);
}

The results are as follows:

@H_ 403_ 111@

If you think the above method is cumbersome, you can use a simpler method, as shown in the following code:

public static void fixedThreadPool() {
    // 创建线程池
    ExecutorService threadPool = Executors.newFixedThreadPool(2);
    // 执行任务
    threadPool.execute(() -> {
        System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
    });
}

2.CachedThreadPool

Create a cacheable thread pool. If the number of threads exceeds the processing requirements, it will be recycled after caching for a period of time. If the number of threads is not enough, a new thread will be created.

Use examples are as follows:

public static void cachedThreadPool() {
    // 创建线程池
    ExecutorService threadPool = Executors.newCachedThreadPool();
    // 执行任务
    for (int i = 0; i < 10; i++) {
        threadPool.execute(() -> {
            System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
        });
    }
}

The results are as follows:

3.SingleThreadExecutor

Create a thread pool with a single number of threads, which can ensure the execution order of first in first out.

Use examples are as follows:

public static void singleThreadExecutor() {
    // 创建线程池
    ExecutorService threadPool = Executors.newSingleThreadExecutor();
    // 执行任务
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + ":任务被执行");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
        });
    }
}

The results are as follows:

4.ScheduledThreadPool

Create a thread pool that can perform deferred tasks.

Use examples are as follows:

public static void scheduledThreadPool() {
    // 创建线程池
    scheduledexecutorservice threadPool = Executors.newScheduledThreadPool(5);
    // 添加定时执行任务(1s 后执行)
    System.out.println("添加任务,时间:" + new Date());
    threadPool.schedule(() -> {
        System.out.println("任务被执行,时间:" + new Date());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
    },1,TimeUnit.SECONDS);
}

The results are as follows:

5.SingleThreadScheduledExecutor

Create a single threaded thread pool that can perform deferred tasks.

Use examples are as follows:

public static void SingleThreadScheduledExecutor() {
    // 创建线程池
    scheduledexecutorservice threadPool = Executors.newSingleThreadScheduledExecutor();
    // 添加定时执行任务(2s 后执行)
    System.out.println("添加任务,2,TimeUnit.SECONDS);
}

The results are as follows:

6.newWorkStealingPool

Create a thread pool for preemptive execution (the task execution order is uncertain). Note that this method can only be used in JDK version 1.8 +.

Use examples are as follows:

public static void workStealingPool() {
    // 创建线程池
    ExecutorService threadPool = Executors.newWorkStealingPool();
    // 执行任务
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());
        });
    }
    // 确保任务执行完成
    while (!threadPool.isTerminated()) {
    }
}

The results are as follows:

7.ThreadPoolExecutor

The most original way to create a thread pool, which contains 7 parameters to set.

Use examples are as follows:

public static void myThreadPoolExecutor() {
    // 创建线程池
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5,10,100,TimeUnit.SECONDS,new LinkedBlockingQueue<>(10));
    // 执行任务
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}

The results are as follows:

Introduction to ThreadPoolExecutor parameter

ThreadPoolExecutor can set up to 7 parameters, as shown in the following code:

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {
     // 省略...
 }

The seven parameters represent the following meanings:

Parameter 1: corepoolsize

Number of core threads, the number of threads that are always alive in the thread pool.

Parameter 2: maximumpoolsize

Maximum number of threads, the maximum number of threads allowed in the thread pool, and the maximum number of threads that can be created when the task queue of the thread pool is full.

Parameter 3: keepalivetime

The maximum number of threads can survive. When there is no task execution in the thread, a part of the maximum thread will be destroyed, and finally the number of core threads will be maintained.

Parameter 4: unit:

The unit is used in conjunction with the survival time of parameter 3. Together, it is used to set the survival time of the thread. There are seven optional time units for parameter keepalivetime:

Parameter 5: workqueue

A blocking queue is used to store tasks waiting to be executed in the thread pool. It is thread safe and includes the following 7 types:

Linkedblockingqueue and synchronous are commonly used. The queuing strategy of thread pool is related to BlockingQueue.

Parameter 6: threadfactory

Thread factory is mainly used to create threads. It defaults to normal priority and non daemon threads.

Parameter 7: handler

Reject policy: the policy for rejecting tasks. The system provides four options:

The default policy is abortpolicy.

Execution flow of thread pool

The execution process of key nodes of ThreadPoolExecutor is as follows:

The execution process of thread pool is shown in the following figure:

Thread reject policy

Let's demonstrate the trigger of the rejection policy of ThreadPoolExecutor. We use the rejection policy of discardpolicy, which will ignore and discard the policy of the current task. The implementation code is as follows:

public static void main(String[] args) {
    // 任务的具体方法
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("当前任务被执行,执行时间:" + new Date() +
                               " 执行线程:" + Thread.currentThread().getName());
            try {
                // 等待 1s
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    // 创建线程,线程的任务队列的长度为 1
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1,new LinkedBlockingQueue<>(1),new ThreadPoolExecutor.DiscardPolicy());
    // 添加并执行 4 个任务
    threadPool.execute(runnable);
    threadPool.execute(runnable);
    threadPool.execute(runnable);
    threadPool.execute(runnable);
}

We created a thread pool with the number of core threads and the maximum number of threads being 1, and set the task queue of the thread pool to 1, so that when we have more than 2 tasks, the rejection policy will be triggered. The execution results are shown in the following figure:

Custom reject policy

In addition to the four rejection policies provided by Java itself, we can also customize the rejection policy. The example code is as follows:

public static void main(String[] args) {
    // 任务的具体方法
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("当前任务被执行,new RejectedExecutionHandler() {
                                                               @Override
                                                               public void rejectedExecution(Runnable r,ThreadPoolExecutor executor) {
                                                                   // 执行自定义拒绝策略的相关操作
                                                                   System.out.println("我是自定义拒绝策略~");
                                                               }
                                                           });
    // 添加并执行 4 个任务
    threadPool.execute(runnable);
    threadPool.execute(runnable);
    threadPool.execute(runnable);
    threadPool.execute(runnable);
}

The execution results of the program are as follows:

What kind of thread pool do you choose?

After the above study, we also have a certain understanding of the whole thread pool. How to select the thread pool?

Let's take a look at the answers given by Alibaba's Java Development Manual:

Therefore, to sum up, we recommend using ThreadPoolExecutor to create a thread pool, because this creation method is more controllable and defines the running rules of the thread pool, which can avoid some unknown risks.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>