In Java language, concurrent programming is implemented by creating thread pools, and there are many ways to create thread pools, each of which corresponds to different usage scenarios. Generally speaking, thread pool creation can be divided into the following two categories:

  • Create thread pools manually through ThreadPoolExecutor.
  • Automatically create a thread pool by using the Executors.

And the above two types of thread pool, and there are 7 specific implementation methods, these 7 implementation methods are:

  1. Executors. NewFixedThreadPool: create a fixed-size thread pool, can control the number of concurrent threads, beyond the thread will be waiting in the queue.
  2. Executors. NewCachedThreadPool: create a cacheable thread pool, if the number of threads than needed for processing, the cache after a period of time will be recycled, if the number of threads is not enough, the new thread.
  3. Executors. NewSingleThreadExecutor: create a single thread pool threads, it can ensure fifo execution order.
  4. Executors. NewScheduledThreadPool: create a delay can perform task thread pool.
  5. Executors. NewSingleThreadScheduledExecutor: create a single thread can perform delay task thread pool.
  6. Executors. NewWorkStealingPool: create a preemptive execution thread pool (task execution order not sure) [add JDK 1.8].
  7. ThreadPoolExecutor: Method of manually creating a thread pool that can be set to a maximum of seven parameters.

Let’s look at the specific uses of each of the seven thread pools.

1.FixedThreadPool

Create a fixed-size thread pool that controls the number of concurrent threads. Create two fixed size thread pools using FixedThreadPool as follows:

public static void fixedThreadPool(a) {
    // Create a pool of 2 threads
    ExecutorService threadPool = Executors.newFixedThreadPool(2);

    // Create a task
    Runnable runnable = new Runnable() {
        @Override
        public void run(a) {
            System.out.println("Task executed, thread :"+ Thread.currentThread().getName()); }};// Thread pool execution tasks (add 4 tasks at a time)
    // There are two methods for executing a task :submit and execute
    threadPool.submit(runnable);  // Submit
    threadPool.execute(runnable); // Execute mode 2:execute
    threadPool.execute(runnable);
    threadPool.execute(runnable);
}
Copy the code

The execution result of the above program is as follows:If the above method is a bit tedious, we can also use the following simple way to create and use the thread pool:

public static void fixedThreadPool(a) {
    // Create a thread pool
    ExecutorService threadPool = Executors.newFixedThreadPool(2);
    // Execute the task
    threadPool.execute(() -> {
        System.out.println("Task executed, thread :" + Thread.currentThread().getName());
    });
}
Copy the code

2.CachedThreadPool

Create a cacheable thread pool. If the number of threads exceeds the required number of threads, the additional threads will be cached for a period of time before being reclaimed. If there are not enough threads, a new thread will be created. The following is an example of the CachedThreadPool command:

public static void cachedThreadPool(a) {
    // Create a thread pool
    ExecutorService threadPool = Executors.newCachedThreadPool();
    // Execute the task
    for (int i = 0; i < 10; i++) {
        threadPool.execute(() -> {
            System.out.println("Task executed, thread :" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch(InterruptedException e) { } }); }}Copy the code

The execution result of the above program is as follows:As you can see from the above results, the thread pool creates 10 threads to perform the corresponding tasks.

Usage scenarios

CachedThreadPool determines the number of threads to be created based on the number of tasks in a short period of time, so it is suitable for processing scenarios with a large number of tasks in a short period of time.

3.SingleThreadExecutor

Create a single thread pool that guarantees first-in, first-out execution. The following is an example of SingleThreadExecutor:

public static void singleThreadExecutor(a) {
    // Create a thread pool
    ExecutorService threadPool = Executors.newSingleThreadExecutor();
    // Execute the task
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + ": Task executed");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch(InterruptedException e) { } }); }}Copy the code

The execution result of the above program is as follows:

What’s the point of a single thread pool?

A single thread pool has two advantages over threads:

  • Can reuse threads: Threads can be reused even from a single thread pool.
  • Provides task management capabilities: a single thread pool also has a task queue, in which multiple tasks can be stored, which is not possible for threads, and when the task queue is full, it can implement a rejection policy, which is not available for threads.

4.ScheduledThreadPool

Create a thread pool that can execute deferred tasks. The following is an example:

public static void scheduledThreadPool(a) {
    // Create a thread pool
    ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
    // Add a scheduled execution task (executed 1s later)
    System.out.println("Add task, time :" + new Date());
    threadPool.schedule(() -> {
        System.out.println("Task executed, time :" + new Date());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
    }, 1, TimeUnit.SECONDS);
}
Copy the code

The execution result of the above program is as follows:As you can see from the above results, the task is executed after 1 second, implementing a 1s delay before executing the task.

5.SingleThreadScheduledExecutor

Create a single-threaded thread pool that can execute deferred tasks, which can be thought of as a single-threaded version of ScheduledThreadPool. An example of its use is as follows:

public static void SingleThreadScheduledExecutor(a) {
    // Create a thread pool
    ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
    // Add a scheduled execution task (execute after 2s)
    System.out.println("Add task, time :" + new Date());
    threadPool.schedule(() -> {
        System.out.println("Task executed, time :" + new Date());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
    }, 2, TimeUnit.SECONDS);
}
Copy the code

The execution result of the above program is as follows:As you can see from the above results, the task was executed after 2 seconds.

6.newWorkStealingPool

Create a thread pool for preemptive execution (tasks executed in an uncertain order). This method is new in JDK 1.8 and is therefore only available in JDK 1.8 or older. Examples of newWorkStealingPool use are as follows:

public static void workStealingPool(a) {
    // Create a thread pool
    ExecutorService threadPool = Executors.newWorkStealingPool();
    // Execute the task
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + "Executed thread name :" + Thread.currentThread().getName());
        });
    }
    // Ensure that the task is completed
    while(! threadPool.isTerminated()) { } }Copy the code

The execution result of the above program is as follows:As you can see from the above results, the order of execution of the tasks is uncertain because it is preemptively executed.

7.ThreadPoolExecutor

ThreadPoolExecutor, the original and most recommended way to manually create a thread pool, provides up to seven parameters that can be set at creation time. The following is an example of ThreadPoolExecutor:

public static void myThreadPoolExecutor(a) {
    // Create a thread pool
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5.10.100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
    // Execute the task
    for (int i = 0; i < 10; i++) {
        final int index = i;
        threadPool.execute(() -> {
            System.out.println(index + "Executed thread name :" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e) { e.printStackTrace(); }}); }}Copy the code

The execution result of the above program is as follows: The advantage of ThreadPoolExecutor over other thread pool creation is that it controls the maximum number of tasks and rejection policies through parameters, making thread pool execution more transparent and controllable, so the Java Development Manual of Alibaba is as follows:

Mandatory: Do not use Executors to create a thread pool. Use ThreadPoolExecutor to clear the running rules of the thread pool and avoid resource depletion.

* If the thread pool object returns by Executors, it has the following disadvantages:

1) FixedThreadPool and SingleThreadPool: The allowed queue length is integer. MAX_VALUE, which may pile up a large number of requests, resulting in OOM.

2) CachedThreadPool: the number of threads allowed to create is integer. MAX_VALUE, which may create a large number of threads, resulting in OOM.

conclusion

There are 7 ways to create a thread pool:

  1. Executors. NewFixedThreadPool: create a fixed-size thread pool, can control the number of concurrent threads, beyond the thread will be waiting in the queue.
  2. Executors. NewCachedThreadPool: create a cacheable thread pool, if the number of threads than needed for processing, the cache after a period of time will be recycled, if the number of threads is not enough, the new thread.
  3. Executors. NewSingleThreadExecutor: create a single thread pool threads, it can ensure fifo execution order.
  4. Executors. NewScheduledThreadPool: create a delay can perform task thread pool.
  5. Executors. NewSingleThreadScheduledExecutor: create a single thread can perform delay task thread pool.
  6. Executors. NewWorkStealingPool: create a preemptive execution thread pool (task execution order not sure) [add JDK 1.8].
  7. ThreadPoolExecutor: Method of manually creating a thread pool that can be set to a maximum of seven parameters.

ThreadPoolExecutor is the last method recommended for creating a thread pool, because it can be used to clarify the rules of the thread pool and avoid the risk of running out of resources.

Judge right and wrong from yourself, praise to listen to others, gain and loss in the number.

Public number: Java interview analysis

Interview collection: gitee.com/mydb/interv…