Analysis of the Principle of Java Thread Pool

     Thread pool is a commonly used function in Java development and is often used in daily development. Do you know how it works? The following is a simple analysis of the principle of the thread pool. Start from the simplest use to analyze the specific implementation and comprehend the basic idea of ​​JDK implementation.

  

  • The easiest way to use the thread pool

             

  ExecutorService service = Executors.newFixedThreadPool(10);
  service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("executor");
            }
        });

      The above is the simplest way to use the thread pool. How does the thread pool run the submitted execution task? Let's analyze it in two steps:

  1. The initialization of the thread pool, the following is the method of initializing the thread pool in the Executors class:

 

        

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

        According to the above newFixedThreadPool method, only a ThreadPoolExecutor object is returned. Note that a key class of the thread pool implemented by the entire JDK is ThreadPoolExecutor, including the ThreadPoolExecutor object that is ultimately initialized by the scheduling thread pool. Then let's take a look at what the constructor of the key class ThreadPoolExecutor does:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

     Judging from the above construction method, the key parameters are checked first. After the conditions are met, the actual parameters or related default parameters passed in by the client are initialized as ThreadPoolExecutor objects and returned to the client.

There are several key parameters for initializing a thread pool

 

Attributes meaning
corePoolSize The minimum size of the thread pool, which is the initialization size.
maximumPoolSize The maximum size of the thread pool. If the number of tasks processed by the current thread pool exceeds this number, the task can only continue to process new submitted tasks after other worker threads are released.

workQueue

Work queue. When the number of tasks submitted by the client to the thread pool is greater than the size of the core thread pool, it will be stored in this queue first.

If the number of tasks submitted by the client to the thread pool is less than the number of cores, it will not be added to the queue, but will directly start a new thread to execute the submitted tasks.

threadFactory thread factory. As the name implies, it is a factory object for creating threads. Users can customize their own thread factories. If they are not specified, the JDK default thread factory is used. The second step is to submit the worker thread


The second step is to submit the worker thread

  service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("executor");
            }
        });

    Why does the run() method execute when the above code is executed ? Let's analyze the server.execute() method.

  1.  Compare whether the currently working worker thread is smaller than the core / minimum thread pool size, here is the 10 specified in our code , if it is smaller, add it to the worker thread pool work task array, and directly start a new thread to execute the task.
  2. If the number of submitted tasks is greater than the size of the core thread pool, the work queue will come in handy at this time, and the submitted tasks will be submitted to the work queue, waiting for idle threads to go to the work queue for task execution.

  3. If it fails to join the work queue, try to add to the Worker thread group and start a new thread to execute the task. If the current thread exceeds the maximum thread pool size, the execution of this task will be rejected and the task execution will fail.

 Overall, a large part of the implementation of the java thread pool is the dependent work blocking queue (BlockingQueue). The default work queue has

 LinkedBlockingQueue SynchronousQueue and many more. The high reuse of threads by the thread pool actually depends on the excellent blocking and wake-up mechanism of the blocking queue.

Let's analyze the implementation mechanism of blocking queue.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326695114&siteId=291194637