How do you know thread pools in the JDK

The thread pool under the JDK and sending packages is a common point of review in interviews, as I wrote earlier in an article on source analysis of ThreadPoolExecutor. Because of the limited space at that time did not say the interview common test points and which points should be mastered. That article is really a bit long, more suitable to use a computer to see, combined with the source code to see. Today, I’m going to talk about some of the things I think a ThreadPoolExecutor should know, the things that are often asked in an interview. Now throw in a few questions, and if you can answer them, you don’t have to read any further.

  1. What are the common parameters in ThreadPoolExecutor and what do they do? After a task is submitted, what policy does a ThreadPoolExecutor follow to create a thread to execute the submitted task?
  2. What states does a ThreadPoolExecutor have, and what does the flow between states look like?
  3. At what point in time is a thread in a ThreadPoolExecutor created? Is it after the task is submitted? Can tasks be created before they are submitted?
  4. When is the thread created in ThreadPoolExecutor started?
  5. ThreadPoolExecutor turns out to be a thread pool so how does it reuse threads?
  6. Can a thread created in a ThreadPoolExecutor execute multiple tasks at the same time? If not, what is the mechanism by which a thread in a ThreadPoolExecutor can only complete one task before it has the chance to execute another?
  7. What is the difference between shutdown and shutdownNow in ThreadPoolExecutor?
  8. Would it be a problem to submit a task to a ThreadPoolExecutor and not call the shutdown or shutdownNow methods when all the tasks have been executed?
  9. Does ThreadPoolExecutor provide extension points to do things before or after the task is executed?

If the answer is up, pass, lol

What does the ThreadPoolExecutor parameter have to do with creating a thread policy?

ThreadPoolExecutor parameters

  • corePoolSizeNumber of core threads in the thread pool
  • mmaximumPoolSizeMaximum number of threads in a thread pool
  • keepAliveTimeHow long is allowed to wait when the number of threads in the thread pool exceeds the corePoolSize to take a task from the workQueue
  • unitKeepAliveTime TimeUnit of the TimeUnit class.
  • workQueueBlock queue used to store submitted tasks when the number of threads in the thread pool exceeds the corePoolSize.
  • threadFactoryThread pool adoption, which creates threads in the thread pool.
  • handlerRejectedExecutionHandler, used when the number of threads in the thread line exceeds maximumPoolSize, to reject execution processors.

Creating a thread Policy

Briefly, after a task is submitted to a thread pool, the pool creates threads to perform the process of submitting the task. When the number of threads in the pool to execute the submitted task is smaller than the corePoolSize, the pool uses a ThreadFacory (thread factory) to create threads to execute the submitted task. Otherwise, go to Step 2. If the number of threads in the pool is larger than the corePoolSize but the workQueue is not full, the pool will save the submitted task to the workQueue. After threads in the waiting thread pool finish executing other submitted tasks, they will loop out tasks from the workQueue for execution. Otherwise, go to Step 3. When the number of tasks in the thread pool is larger than corePoolSize and the workQueu is full, but not more than maximunPoolSize, the thread pool uses ThreadFacory to create threads to execute the submitted task. Otherwise, go to 4. When a task is submitted to a thread pool with a value greater than maximunPoolSize, it executes the RejectedExecutionHanlder policy configured in the thread pool. You must be careful when setting ThreadPoolExecutor parameters. A large ArrayBlockQueue or an unlimited LinkedBlockQueue is not recommended, and corePoolSize should not be too large. CPU intensive tasks can be set to smaller (CUP data +1) to avoid unnecessary context switching; For IO intensive tasks, corePoolSize can be set to a larger size to avoid long I/O waits while the CPU is idle. You are advised to use a custom threadFactory to create threads that are easily distinguishable to help locate problems.

What states does the thread pool have, and what does the flow between states look like?

  • RUNNING: RUNNING, receiving new tasks or processing tasks in the queue.
  • SHUTDOWN: the system stops receiving new tasks but processes tasks in the queue with the value 0.
  • STOP: Stops receiving new tasks, does not process tasks in the queue, and interrupts tasks in progress.
  • TIDYING: all tasks terminated queue size is 0, threads transiting TIDYING state will execute terminated() method.
  • TERMINATED: TERMINATED () has been executed. The status flow is as follows:

At what point in time is a thread in a pool created?

At what point in time is a thread in a ThreadPoolExecutor created? Is it after the task is submitted? Can tasks be created before they are submitted? Normally, the pool uses a thread factory to create threads after the task is submitted, but not when the number of threads in the pool is corePoolSize or maxmumPoolSize. You can pre-create a core thread before the task is submitted using either the prestartCoreThread method or the prestartAllCoreThreads method. Specifically, you can refer to this diagram:

When is the thread created in ThreadPoolExecutor started?

The thread implementation in the thread pool is created in the addWorker method, which is analyzed in the previous article. Once created, the thread is started. The threads created in the thread pool are encapsulated in the Worker object, and the Worker class implements the Runnable interface, and the threads in the thread pool reference the Worker. When a thread is started, it actually has the opportunity to wait for the operating system to schedule the execution of the run method of the Worker class.

Worker(Runnable firstTask) { setState(-1); this.firstTask = firstTask; Thread = getThreadFactory().newThread(this); // Create a thread that references worker this.thread = getThreadFactory().newThread(this); }Copy the code

ThreadPoolExecutor turns out to be a thread pool so how does it reuse threads?

Once the thread pool has created a thread from the ThreadFactory, it encapsulates the created thread into the Worker object and starts the thread. The newly created thread will execute the task that has just been submitted, and it will continuously fetch and execute the task from the workerQueue. The thread reuse of the thread pool is achieved by continuously fetching tasks from the workerQueue for execution. See runWorkers method analysis for source code analysis.

Can a thread created in a ThreadPoolExecutor execute multiple tasks at the same time?

You cannot perform multiple tasks at a time. You can perform another task only when one task is completed. The thread created by ThreadFacory in the thread pool is finally encapsulated in the Worker, and the thread refers to the Worker. After the start thread, the task is actually executed in the run method of the Worker. Finally, the run agents task execution to the runWorker method of the ThreadPoolExecutor.

private final class Worker extends AbstractQueuedSynchronizer implements Runnable {... }Copy the code

Worder implements Runnable on the one hand and inherits AQS on the other. By implementing AQS, the Worker has the semantics of exclusive lock. Every time when the task is submitted, the Worker will lock and unlock after the task is finished. It is this locking and unlocking operation that ensures that the same thread is not allowed to perform another task until the current one has finished.

What is the difference between shutdown and shutdownNow in ThreadPoolExecutor?

The shutdown method sets the status of the thread pool to shutdown. In this case, a new task cannot be submitted (the invocation throws an exception), the workerQueue will continue to execute, and the pool will send an interrupt signal to any idle threads. An idle thread is not actually the thread that is executing the task. How the thread encapsulated in the worker can be locked, here the thread implementation will be idle. The following is to send out interrupt signal to idle thread source code.

private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) { Thread t = w.thread; // w.threadLock () is used to lock and see if the thread is executing. t.isInterrupted() && w.tryLock()) { try { t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne) break; } } finally { mainLock.unlock(); }}Copy the code

The shutdownNow method sets the state of the thread pool to STOP, at which point a new task cannot be committed (the fetching throws an exception), and all threads in the thread pool receive an interrupt signal. Depending on how the thread responds, if the thread blocks by calling Object’s wait, join, or its own sleep method, the interrupted status is cleared and InterruptedException is thrown. For other cases, see the description of thread.interrupt. The shutdownNow method sends an interrupt message to all threads.

private void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; // The lock operation ensures that no new woker is created during interruption. Mainlock.lock (); try { for (Worker w : workers) w.interruptIfStarted(); } finally { mainLock.unlock(); }}Copy the code

Would it be a problem to submit a task to a ThreadPoolExecutor and not call the shutdown or shutdownNow methods when all the tasks have been executed?

Allowing a timeout without referring to the core thread will be a problem. Is the core thread allowed to time out when getting a task from the wokerQueue by blocking and waiting for it to arrive, or by setting a timeout to get a task from the synchronously blocked queue? Whether to get the task from the Poll method of BlockingQueue or from the take method. Refer to the getTask method analysis in the previous source analysis. If the shutdown or shutdownNow methods are not called, the core thread will remain blocked and suspended because it calls BlockingQueue. Take in the getTask method to get the task. The core thread will always be blocked, causing a memory leak, and the main thread will not exit unless forced to kill. Try to run the following program and you will find that the program cannot exit.

public class Test { public static void main(String args[]) { ExecutorService executorService = new ThreadPoolExecutor(3, 3, 10 L, TimeUnit. SECONDS, new ArrayBlockingQueue < Runnable > (10)); executorService.submit(new Runnable() { @Override public void run() { System.out.println("thread name " + Thread.currentThread().getName()); }}); }}Copy the code

When using a thread pool, remember to use the shutdown or shutdownNow method to shutdown the thread pool in the specific scenario. The shutdown method is applicable to the scenario where the submitted task is completed, and the shutdownNow method is applicable to the scenario where the submitted task is not completed.

Does ThreadPoolExecutor provide extension points to do things before or after the task is executed?

The thread pool provides three extension points: beforeExecutor and afaterExecutor, before and after the run or call method of the submitted task is called. Another extension point is that the TERMINATED method is called when the thread pool’s state flows from TIDYING state to TERMINATED state.

conclusion

Originally just want to write a little bit, write write find a little long. This article mainly introduces the points that I think are important in ThreadPoolExecutor, and it is also a review of the parts of ThreadPoolExecutor that I have found to be biased.

Read three things ❤️

If you found this post helpful, I’d like to invite you to do three small favors for me:

  1. Likes, retweets, and your “likes and comments” are what drive me to create.

  2. Follow the public account “Java rotten pigskin”, irregularly share original knowledge.

  3. In the meantime, look forward to a follow-up article at ing🚀

! [](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d0f04480b10490abe49900a076ee66f~tplv-k3u1fbpfcp-zoom-1.image)

Author: Ye Yi reference: club.perfma.com/article/191…