Detailed introduction of four common thread pools in Java

  • 2021-07-03 00:07:29
  • OfStack

1. Introduction to Thread Pool

1. Thread pool concept:

Thread pool is to create 1 threads first, and their collection is called thread pool. Using thread pool can improve performance very well. When the system starts, the thread pool creates a large number of idle threads. When the program passes a task to the thread pool, the thread pool will start a thread to execute this task. After the execution, the thread will not die, but return to the thread pool again to become idle, waiting for the next task to be executed.

2. How Thread Pool Works

2.1 In the programming mode of thread pool, the task is submitted to the whole thread pool, instead of directly submitting to a certain thread. After the thread pool gets the task, it will look internally for whether there are idle threads, and if there are, it will hand over the task to a certain idle thread.

2.2 One thread can only perform one task at a time, but multiple tasks can be submitted to one thread pool at the same time.

3. Reasons for using thread pools:

Multi-threaded running time, the system constantly starts and closes new threads, the cost is very high, which will consume system resources excessively, and the danger of switching threads excessively, which may lead to the collapse of system resources. At this time, the thread pool is the best choice.

2. Detailed explanation of 4 common thread pools

1. Introduction to the return value of thread pool ExecutorService:

ExecutorService Is a class provided by Java for managing thread pools. Two functions of this class: control the number of threads and reuse threads

2. The specific four commonly used thread pool implementations are as follows: (The return values are all ExecutorService)

2.1 Executors.newCacheThreadPool() : Can cache thread pool, first check whether there are previously established threads in the pool, and if so, use it directly. If not, a new thread is created and added to the pool. The cache pool is usually used to perform asynchronous tasks with short lifetime

Sample code:


package com.study.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
  public static void main(String[] args) {
   // Create 1 Cacheable thread pool 
   ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
   for (int i = 0; i < 10; i++) {
     try {
       //sleep It is obvious that the previous threads in the thread pool are used, and no new threads are created 
       Thread.sleep(1000);
     } catch (InterruptedException e) {
       e.printStackTrace();
      }
     cachedThreadPool.execute(new Runnable() {
       public void run() {
    // Print the information of the executing cache thread 
          System.out.println(Thread.currentThread().getName()+" Being executed ");
       }
      });
    }
  }
}

Output:

pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 being executed
pool-1-thread-1 is being executed

The thread pool is infinite. When the last 1 task has been completed when the current task is executed, the thread executing the last 1 task will be reused instead of creating a new thread every time

2.2 Executors.newFixedThreadPool(int n) Create a pool of reusable threads with a fixed number, and run these threads in a shared unbounded queue.

Sample code:


package com.study.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
    // Create 1 A fixed number of thread pools can be reused 
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
     fixedThreadPool.execute(new Runnable() {
        public void run() {
          try {
           // Print the information of the executing cache thread 
           System.out.println(Thread.currentThread().getName()+" Being executed ");
           Thread.sleep(2000);
         } catch (InterruptedException e) {
           e.printStackTrace();
          }
        }
     });
    }
  }
}

Output:

pool-1-thread-1 being executed
pool-1-thread-2 being executed
pool-1-thread-3 being executed
pool-1-thread-1 is being executed
pool-1-thread-2 being executed
pool-1-thread-3 being executed
pool-1-thread-1 being executed
pool-1-thread-2 being executed
pool-1-thread-3 being executed
pool-1-thread-1 being executed

Because the thread pool size is 3, sleep is 2 seconds after each task outputs the print result, so three results are printed every two seconds.

The size of the fixed-length thread pool is best set according to system resources. Such as Runtime.getRuntime().availableProcessors()

2.3 Executors.newScheduledThreadPool(int n) Create a fixed-length thread pool to support timed and periodic task execution

Delayed execution of the sample code:


package com.study.test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
  public static void main(String[] args) {
    // Create 1 Fixed-length thread pool, supporting timed and periodic task execution-delayed execution 
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    // Delay 1 Second execution 
    scheduledThreadPool.schedule(new Runnable() {
      public void run() {
        System.out.println(" Delay 1 Second execution ");
      }
    }, 1, TimeUnit.SECONDS);
   }
}

Output:

Delay execution by 1 second

Execute the sample code periodically:


package com.study.test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
  public static void main(String[] args) {
    // Create 1 Fixed-length thread pool, supporting timed and periodic task execution-regular execution 
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    // Delay 1 Every second after 3 Second execution 1 Times 
    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
       public void run() {
        System.out.println(" Delay 1 Every second after 3 Second execution 1 Times ");
      }
    }, 1, 3, TimeUnit.SECONDS);
  }
}

Output:

Execute once every 3 seconds after 1 second delay
Execute once every 3 seconds after 1 second delay
.............

2.4 Executors.newSingleThreadExecutor() Creates a single-threaded thread pool that executes tasks with only one worker thread, ensuring that all tasks are executed in the specified order (FIFO, LIFO, priority).

Sample code:


package com.study.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestThreadPoolExecutor {
  public static void main(String[] args) {
    // Create 1 Single-threaded thread pool 
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
      final int index = i;
       singleThreadExecutor.execute(new Runnable() {
        public void run() {
          try {
            // The results are output in turn, which is equivalent to executing each task in sequence 
            System.out.println(Thread.currentThread().getName()+" Being executed , The printed value is :"+index);
            Thread.sleep(1000);
          } catch (InterruptedException e) {
             e.printStackTrace();
          }
        }
       });
    }
   }
}

Output:

pool-1-thread-1 is being executed and the printed value is: 0
pool-1-thread-1 is being executed and the printed value is: 1
pool-1-thread-1 is being executed, and the printed value is: 2
pool-1-thread-1 is being executed, and the printed value is: 3
pool-1-thread-1 is being executed, and the printed value is: 4
pool-1-thread-1 is being executed, and the printed value is: 5
pool-1-thread-1 is being executed, and the printed value is: 6
pool-1-thread-1 is being executed, and the printed value is: 7
pool-1-thread-1 is being executed, and the printed value is: 8
pool-1-thread-1 is being executed, and the printed value is: 9

3. Buffer queue BlockingQueue and custom thread pool ThreadPoolExecutor

1. Introduction to Buffer Queue BlockingQueue:

BlockingQueue is a double buffered queue. BlockingQueue uses two queues internally, allowing two threads to store and take out one operation to the queue at the same time. While ensuring concurrency security, it improves the access efficiency of queues.

2. Several commonly used BlockingQueue:

ArrayBlockingQueue (int i): A specified size BlockingQueue whose construction must specify a size. The objects it contains are sorted in FIFO order. LinkedBlockingQueue () or (int i): The size of BlockingQueue is not fixed. If the size is specified when it is constructed, the generated BlockingQueue has a size limit, and the size is determined by Integer. MAX_VALUE. The objects it contains are sorted in FIFO order. PriorityBlockingQueue () or (int i): Similar to LinkedBlockingQueue, but the ordering of the objects it contains is not FIFO, but is determined by the natural order of the objects or the Comparator of the constructor. SynchronizedQueue (): Special BlockingQueue, which must be operated alternately by placing and fetching.

3. Custom thread pool (ThreadPoolExecutor with BlockingQueue):

Custom thread pools, which can be created using the ThreadPoolExecutor class, have multiple constructors to create thread pools.

Common constructors: ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)

Sample code:


package com.study.test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
class TempThread implements Runnable {
  @Override
  public void run() {
    //  Print the information of the executing cache thread 
    System.out.println(Thread.currentThread().getName() + " Being executed ");
     try {
      // sleep1 Second guarantee 3 Tasks are in the 3 Execute on three threads 
      Thread.sleep(1000);
     } catch (InterruptedException e) {
       e.printStackTrace();
    }
   } 
}
public class TestThreadPoolExecutor {
  public static void main(String[] args) {
    //  Create an array buffer wait queue 
    BlockingQueue<Runnable> bq = new ArrayBlockingQueue<Runnable>(10);
    // ThreadPoolExecutor: Create a custom thread pool with the number of threads saved in the pool 3 The maximum number of threads allowed is 6
    ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 6, 50, TimeUnit.MILLISECONDS, bq);
    //  Create 3 Tasks 
     Runnable t1 = new TempThread();
     Runnable t2 = new TempThread();
     Runnable t3 = new TempThread();
     // Runnable t4 = new TempThread();
     // Runnable t5 = new TempThread();
     // Runnable t6 = new TempThread(); 
     // 3 Tasks are in the 3 Execute on three threads 
     tpe.execute(t1);
     tpe.execute(t2);
     tpe.execute(t3);
     // tpe.execute(t4);
     // tpe.execute(t5);
     // tpe.execute(t6); 
     //  Close custom thread pool 
     tpe.shutdown();
   }
}

Output:

pool-1-thread-1 being executed
pool-1-thread-2 being executed
pool-1-thread-3 being executed

Summarize


Related articles: