This article is from the blog Vander, CSDN blog, if you need to reprint please indicate the source, respect the original thank you

Blog Address:Blog.csdn.net/l540675759/…

preface

(1) This paper spent 2 weeks and 3 days in the wee hours, which is a lot of time to learn. (2) From sorting out the article, the author from thread -> blocking queue -> binary -> internal mechanism of thread pool, all the way, originally intended to write an article to lay the foundation for AsyncTask, unexpectedly wrote more and more. (3) If there is any mistake in the article, please correct it in time, and the author will update it in time. (4) I hope you can learn from the article. Get a lot. By far, the blogger's best post is also the one that put a lot of effort into it.Copy the code

thread

Before we get into thread pools, let’s introduce the concept of threads:

Watching TV is the main line in the picture. The user wants to finish the operation of boiling water while watching TV without wasting time watching TV. After reading this picture, the concept of main thread and sub-thread will be better understood.

What is a thread?

At the bottom, a thread is a single flow of sequential control in a process.

A single process can have multiple concurrent tasks, each of which acts as if it has its own CPU. The underlying mechanism is to split CPU time, which means that the CPU allocates its occupied time to each task in turn.

Each task feels like it is using CPU all the time, when in fact it is slicing up CPU time among all tasks.

In the environment of multiple CPUS, the operation of multithreading can greatly provide the running speed of the program, which is the meaning of the existence of threads.


So what does a thread do in Android?

First of all, let’s take a look at the concept of threads and processes under Android: here is Gityuan’s answer on Zhihu about threads and processes

Process: Before each app runs, a process is created. This process is produced by Zygote fork, which is used to host various activities/services and other components running on the app. Processes are completely transparent to the top applications, which is a deliberate move by Google to make apps run in the Android Runtime. In most cases an App runs in a process, unless the Android: Process attribute is configured in androidmanifest.xml, or the process is forked through native code.

Threads: Threads are common in applications, such as creating a new Thread each time a new Thread().start is created. From the perspective of Linux, there is no essential difference between a process and a thread except whether they share resources. They are both a task_struct structure. In the view of CPU, a process or thread is nothing more than a piece of executable code. Ensure that each task has as fair a slice of CPU time as possible.


Here’s a quick summary of what threads can do on Android:

(1) In Android, threads are divided into main thread and sub-thread. The main thread, also known as UI thread, is used to deal with various things related to the interface, such as interface loading and Activity life cycle, which are all within the scope of the main thread.

(2) Because the main thread is special, because the main thread itself spends most of the consumption on the processing interface, so the main thread can no longer process too time-consuming operations (IO operations, network requests, a large number of data operations), otherwise it will cause ANR phenomenon (program stuck).

What is ANR? There is a complete introduction on Baidu here

The main reasons for this phenomenon are as follows:

The Activity response time exceeds 5s

Broadcast takes longer than 10 seconds to process

The Service processing time exceeds 20 seconds

This is mostly due to time-consuming operations on the main thread, because activities, Broadcast, and Serivce themselves are carried by the main thread.

(3) At this point, the child thread is suddenly born to solve this problem. Android recommends that time-consuming operations be run in the child thread.

(4) In Android, AsyncTask, HandlerThread and IntentService can solve the time-consuming problem in addition to threads, but they are still traditional threads in nature.


Why is there a thread pool?

A thread pool is literally a pool that holds and manages threads. So why is there a thread pool?

Let’s start with an example where I use Handler and Thread to simulate network requests:

private Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (MSG. What = = TASK_ACTION) {the d (" received information ", "update UI"); } return false; }});Copy the code
New Thread(new Runnable() {@override public void run() {try {thread.sleep (1000); mHandler.sendEmptyMessage(TASK_ACTION); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();Copy the code

In this process, a Thread is used to simulate a normal network request, and then the UI Thread is called back and forth by the Handler to tell the UI Thread to refresh.

A good article introducing Handler

There is only one network request above, so now the requirement comes, the interface may have more than one network request, there may be a large number of network requests, this will cause problems:

(1) When a large number of network requests are generated, a large number of threads will be created and destroyed, which may cause excessive performance overhead.

(2) When a large number of threads work together, resources may be tight. The underlying mechanism of threads is to divide CPU time, which has been introduced above. When a large number of threads exist at the same time, resources may be occupied by each other, resulting in blocking.

Based on the above background, the appropriate Thread pool can be a very good solution to solve the above problems, and the simulated network request is a simple example, and real cases, there will be a good many things similar to the above, such as the great data in database operations, multi-threaded download, at the same time of using Thread will appear the above situation.


What is a thread pool?

The idea of a thread pool in Android comes from Java’s Executor, which is an interface. The real implementation of a thread pool is ThreadPoolExecutor, which provides a set of parameters to configure the thread pool. Different thread pools can be created with different parameters.

Advantages of thread pools:

The emergence of thread pool is exactly the pain point to solve the above similar problems, and the advantages of thread pool are:

(1) Reuse threads in the thread pool to avoid performance overhead caused by thread creation and destruction.

(2) It can effectively control the maximum number of concurrent threads in the thread pool and avoid the blocking phenomenon caused by the mutual preemption of system resources between large numbers of threads.

(3) Can be simple management of threads, and provide periodic execution and specified interval cycle execution and other functions.


Thread pool constructor

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                    BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory)Copy the code

The above code is the parameters needed to create a basic thread pool. Let’s use the diagram to briefly describe it:

The figure above briefly describes the parameters needed to create a basic thread pool and the meanings of each parameter. The meanings of each parameter will be explained in detail below.


CorePoolSize Specifies the number of core threads.

By default, the number of core threads lives on in the thread, even if they are idle.

If the allowCoreThreadTimeOut property of ThreadPoolExecutor is set to true, then the core thread has a timeout policy, which is determined by keepAliveTime, When the wait time exceeds the duration specified by keepAliveTime, the core thread is stopped.


MaximumPoolSize Maximum number of threads that a thread pool can hold.

When the number of active threads reaches this value, subsequent new tasks will be blocked.


KeepAliveTime Specifies the timeout duration for which a non-core thread is idle, beyond which it is reclaimed. When allowCoreThreadTimeOut is set to True, KeepAliveTime also applies to the core thread.


Unit specifies the unit of keepAliveTime. This is an enumeration, and is used for timeunit.milliseconds, timeunit.seconds, and timeunit.minutes.

Timeunit. NANOSECONDS timeunit. MICROSECONDS timeunit. MILLISECONDS timeunit. SECONDS timeunit. MINUTES Timeunit. HOURS HOURS timeunit. DAYS DAYSCopy the code

WorkQueue Specifies the queue of tasks in the thread pool. Runnable objects submitted through the thread pool execute method are stored in this parameter.

This task queue is of the type BlockQueue and belongs to a blocking queue. When the queue is empty, fetching tasks will be blocked. When the queue is full, adding tasks will also be blocked.

Check out this article: Java Multithreading tools -BlockingQueue


ThreadFactory a threadFactory that provides the ability to create new threads for a thread pool. ThreadFactory is an interface that has only one method, newThread (Runnable R), to create threads.

ThreadFactory Factory =new ThreadFactory() {private final AtomicInteger mCount =new AtomicInteger(1);  @Override public Thread newThread(Runnable r) { return new Thread(r, "new Thread #" + mCount.getAndIncrement()); }};Copy the code

Thread pool source code parsing

Open source, the thread pool source code in addition to the construction parameters, some of the other basic attributes, first to analyze.

The thread pool life cycle

Private final AtomicInteger CTL = new private final AtomicInteger CTL = new AtomicInteger(ctlOf(RUNNING, 0)); SIZE =32 bits private static final int COUNT_BITS = integer.size - 3; Private static final int CAPACITY = (1 << COUNT_BITS) -1; private static final int CAPACITY = (1 << COUNT_BITS) -1; Private static final int RUNNING = -1 << COUNT_BITS; private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;Copy the code

To do this, you shift 0, 1, and other values 29 bits to the left in binary, and fill the gaps with zeros. The actual result is:

RUNNING = 111 000... 000 (29 zeros) # does not accept new tasks, but will process the status of queue tasks. SHUTDOWN = 000 000... # STOP = 001 000 # STOP = 001 000 # STOP = 001 000 # STOP = 001 000 All threads in the thread pool are terminated and the workCount is cleared to zero. In this state the terminated() method TIDYING = 010 000 is run. 000 (29 zeros) # terminated() method and state terminated = 011 000... 000 (29 0)Copy the code
Private static int runStateOf(int c) {return c & ~CAPACITY; } private static int workerCountOf(int c) {return c & CAPACITY; * * *} / stitching thread through calculation or life cycle of the state and the number of worker threads * / private static int ctlOf (int the rs, int wc) {return rs | wc. }Copy the code

(1) ctlOf() takes two parameters, one is the life cycle state, the other is the current thread pool worker thread. Life cycle state format: XXX 0000… 0000(29 zeros) ctlOf() returns a value that converts the number of worker threads to base 2 concatenated on the second half of the binary of the lifecycle.

(2) The runStateOf() and workerCountOf() methods are used to evaluate the life cycle state values with CAPACITY and the CAPACITY inverse. In short, we get the high (first three) and low (last 29) bits of binary numbers.

If you are familiar with bit operations, you can find:

CAPACITY ------> 000 1111... 1111 ~CAPACITY ------> 111 0000... 0000 (29 0)Copy the code

Therefore, the first 3 bits and the last 29 bits can be taken out to represent the life cycle of the thread pool and the number of worker threads respectively during the operation of and.


Other attributes

Private static Final RejectedExecutionHandler defaultHandler = new AbortPolicy();Copy the code

When the thread pool fails to execute a task, it may be because the task queue is full or the task cannot execute successfully. ThreadPoolExecution then calls the handler’s rejectedExecution method to notify the caller.

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());  }Copy the code

By default, rejectedExecution throws a RejectedExecutionException abnormalities, why currently unable to perform a task.

ThreadPoolExecution for RejectedExecutionException provides several optional value:

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- CallerRunsPolicy -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / refused to task, judge whether the state of the thread pool for SHUTDOWN, if it is a task will be discarded, if not task will be to continue. public void rejectedExecution(Runnable r, ThreadPoolExecutor e){ if (! e.isShutdown()) { r.run(); }} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- AbortPolicy (default) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - / / refused to task, directly responsible for an exception is thrown and public void rejectedExecution(Runnable r, ThreadPoolExecutor e){ throw new RejectedExecutionException( "Task " + r.toString() + " rejected from " +e.toString()); } -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- DiscardPolicy -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - / / is simply refused to task, and nothing happens, the task will also lost public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {/ / what didn't happen} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- DiscardOldestPolicy -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Public void rejectedExecution(Runnable r, Runnable r, if yes, the task will be discarded. If no, the task with the longest waiting time in the queue will be ejected and added to the queue. ThreadPoolExecutor e){ if (! e.isShutdown()) { e.getQueue().poll(); e.execute(r); }}Copy the code

More important method

The thread pool has two methods to execute, submit() and execute(), which essentially have the same meaning.

As can be seen from the figure,submit() still needs to call execute() to execute the task, while the essential difference between submit() and execute() is that submit() returns the wrapped task.

submit()

public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); Execute execute(ftask); // The wrapped Runable returns ftask; } // Wrap Callable<T> in FutureTask protected <T> RunnableFuture<T> newTaskFor(Callable<T> Callable) {return new FutureTask<T>(callable); Public class FutureTask<V> implements RunnableFuture<V> public class FutureTask<V> implements RunnableFuture {... } public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }Copy the code

execute()

public void execute(Runnable command) { if (command == null) throw new NullPointerException(); Int c = ctl.get(); If (workerCountOf(c) < corePoolSize) {if (workerCountOf(c) < corePoolSize) {if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true)) return; c = ctl.get(); If (isRunning(c) && workqueue.offer (command)) {int recheck = ctl.get(); // Check thread pool status, if not RUNNING, remove queue if (! isRunning(recheck) && remove(command)) reject(command); Else if (workerCountOf(recheck) == 0) addWorker(null, false); } // If the above conditions are not met, try to create a non-core thread to execute the task, and if this fails, call reject(). Else if (! addWorker(command, false)) reject(command); }Copy the code

Here is the basic flow of the execute() method:

As you can see from the execute() method, the addWorker() method is the primary method for creating threads (core, non-core), while the reject() method is a callback for thread creation failures.


reject()

Let’s look at the Reject () method, which sends the notification through the Handler above. Then according to different types of RejectedExecutionHandler, different treatment, here we have introduced above.

    final void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }
Copy the code

Let’s focus on the thread creation method: addWorker()

Parameters:

Runnable firstTask:

You can also set it to NULL for incoming tasks (in the case of SHUTDOWN, simply create a thread to execute the task).

boolean core:

Whether the thread to be created needs to be a core thread.

private boolean addWorker(Runnable firstTask, Boolean core) {/ / similar to goto, is a Java identifier, appearance here is to prevent in a multi-threaded, compareAndIncrementWorkerCount (), to calculate the thread pool status, problems, and to set up the retry keyword. Retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); // the thread is already stopped or about to be stopped // the thread is SHUTDOWN, and the task passed is null. In this case, the queue is not empty and the thread needs to be added If (rs >= SHUTDOWN &&! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false; // Determine whether the current number of worker threads exceeds the maximum number of core threads or the maximum number of threads, depending on the second Boolean variable for (;;). { int wc = workerCountOf(c); if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; / / this function is to judge the state of the thread pool statistics into no success/update/if success directly out of the loop, continue to implement the if (compareAndIncrementWorkerCount (c)) break retry. c = ctl.get(); // Re-read ctl if (runStateOf(c) ! = rs) continue retry; Retry inner loop}} //Worker is a wrapper class for threads. boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try { w = new Worker(firstTask); final Thread t = w.thread; if (t ! Final ReentrantLock mainLock = this.mainLock; final ReentrantLock mainLock; mainLock.lock(); try { int rs = runStateOf(ctl.get()); Thread pool creates threads in only two cases: //1. The thread pool is RUNNING (rs<SHUTDOWN) //2. Thread pool is in SHUTDOWN state, and the task is null, this task queue is not empty, however, need to continue to increase the thread to speed the progress. If (rs < SHUTDOWN | | (rs = = SHUTDOWN && firstTask = = null)) { / / here is to check the Thread state, to prevent the accident. The if (t.i sAlive ()) throw new IllegalThreadStateException (); workers.add(w); Int s = worker.size (); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } // If the thread has been added successfully, then set the flag if (workerAdded) {t.start(); workerStarted = true; }}} finally {// If the thread does not start, it will be sent to the adding thread. workerStarted) addWorkerFailed(w); } // Return true on success, false on failure. Return workerStarted; }Copy the code

Notes of the addWorker() method:

If a thread is successfully added to perform the current task, the state of the current thread pool is flushed. If a thread is successfully added to perform the current task, the state of the current thread pool is flushed. If a thread is successfully added to perform the current task, the state of the current thread pool is flushed. This method returns false when the thread factory fails to create a thread. This method returns false when the thread factory fails to create a thread. (6) If the thread factory returns a null thread due to a thread creation failure, or an exception occurs (usually due to an OOM during thread execution), the thread pool will be rolled back.Copy the code


Several phases of the execution of the addWorker() method

Stage 1:

State examination (mmse)

In TERMINATED state, the thread pool is TERMINATED to prevent the thread from being stopped,TIDYING, or TERMINATED. False is returned if the thread is TERMINATED. Then, for the SHUTDOWN state, only the current task queue is not empty, and the task parameter passed is NULL. Threads can be created in this state to perform the rest of the task, otherwise return false.Copy the code
   if (rs >= SHUTDOWN &&! (rs == SHUTDOWN && firstTask == null 
            &&! workQueue.isEmpty()))
                return false;Copy the code

Stage 2:

Add checks to determine whether threads can be created from the current thread pool and the number of threads that can be created

(1) Whether the number of current threads exceeds the maximum capacity of the thread pool, and whether it exceeds the set number of core threads and the maximum number of threads according to the core parameter. (2) after the first step you can create a thread, here need compareAndIncrementWorkerCount () by atomic operations to update the thread pool thread count change, if change the number fails, there is a retry mechanism, retry this keyword is to complete this operation. CAPACITY = 1>> 29-1 =2^29-1Copy the code
for (;;) { int wc = workerCountOf(c); if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; if (compareAndIncrementWorkerCount(c)) break retry; c = ctl.get(); // Re-read ctl if (runStateOf(c) ! = rs) continue retry; }Copy the code

Stage 3:

Create a thread

Boolean workerStarted = false; Boolean workerStarted = false; boolean workerAdded = false; Return true if the final thread was created and added successfully, or call the addWorkerFailed() method if the thread was not finally run. Since the logic is not complicated, I won't post the code here.Copy the code

Other related methods

addWorkedFailed()

In the addWorker() method, the addWorkedFailed() method is called if there is no final run (workerStarted=false) after the thread is created.

/** * Roll back the creation of the Worker thread: * 1. Remove the wrapper class Worker of the thread if it exists. * 2. Remove the Worker that fails to add the thread, and the number of current Worker threads that need to be refreshed * 3. */ private void addWorkerFailed(Worker w) {final ReentrantLock mainLock = this.mainlock; mainLock.lock(); try { if (w ! = null) workers.remove(w); decrementWorkerCount(); // Try to stop the operation. TryTerminate (); } finally { mainLock.unlock(); }}Copy the code

tryTerminate()

In the addWorkedFailed() method, we see that in addition to the rollback, it also calls tryTerminate() in an attempt to stop the thread pool. Since thread pool creation failures are usually caused by an exception (or OOM), this is the time to stop the thread pool.

Matters needing attention:

This method TERMINATED the thread pool in two TERMINATED cases: 1.SHUTDOWN, queue empty 2.STOP. If the above conditions are met, the termination state can be changed, which interrupts the idle threads in the current thread pool to ensure the transmission of the termination signal.Copy the code
final void tryTerminate() { for (;;) { int c = ctl.get(); / / testing is currently RUNNING state, or state has stopped (TERMINATED), or SHUTDOWN state, the queue is not empty. The if (set (c) | | runStateAtLeast (c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) return; If (workerCountOf(c)! WorkerCountOf (c)! = 0) { interruptIdleWorkers(ONLY_ONE); return; } final ReentrantLock mainLock = this.mainLock; mainLock.lock(); If (ctl.compareAndSet(c, ctlOf(TIDYING, ctlOf)) 0))) {try {// Stop the empty implementation of the method terminated(); } finally {// The thread pool is set to TERMINATED ctl.set(ctlOf(TERMINATED, 0)); // Set the flag that the lock can be re-entered to wake up all threads waiting outside the lock. abortion.signalAll (); } return; } } finally { mainLock.unlock(); }}}Copy the code

interruptIdleWorkers()

In the tryTerminate() method, the interrupt thread is performed by the interruptIdleWorkers() method.

The onlyOne argument is the onlyOne that sets the thread interrupt action:

If true, only one thread of the worker thread is interrupted. If false, all worker threads are interrupted.Copy the code
private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) { Thread t = w.thread; // Check thread status if (! t.isInterrupted() && w.tryLock()) { try { t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); If (onlyOne) break; if (onlyOne) break; if (onlyOne) break; } } finally { mainLock.unlock(); }}Copy the code

The shutdown() method, which interrupts all idle threads, is the shutdown() method, which still calls interruptIdleWorkers().

public void shutdown() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); CheckShutdownAccess (); // Set the thread pool state to SHUTDOWN advanceRunState(SHUTDOWN); // Stop all idle processes. Call interruptIdleWorkers (false); interruptIdleWorkers(); // Need to implement their own, interrupt all thread customizable operation onShutdown(); } finally { mainLock.unlock(); } tryTerminate(); }Copy the code

Note: (1) When shutdown() is executed, existing tasks can be executed, but new tasks will not be processed.

(2) If the SHUTDOWN state is already in place, continuing the call will have no effect.

(3) This method does not wait for all tasks to complete before committing. If you want all tasks to complete first, use awaitTermination().


awaitTermination()

Block until the current task is complete, the request is not closed, or a timeout occurs, or the thread is interrupted to see which occurs faster.

Parameter :d timeout – – Set the timeout period unit – – Set the unit of the timeout period

public boolean awaitTermination(long timeout, TimeUnit Unit) throws InterruptedException {// Set the time long nanos = unit.tonanos (timeout); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); // This is an infinite loop. When the thread pool is TERMINATED, exit from the loop returns true, indicating that all tasks are completed. Otherwise timeout or thread interrupt returns false. While (! runStateAtLeast(ctl.get(), TERMINATED)) { if (nanos <= 0L) return false; nanos = termination.awaitNanos(nanos); } return true; } finally { mainLock.unlock(); }}Copy the code

Classification of thread pools

The four most common types of thread pools in Android have different features:

1.FixedThreadPool

/ / features: Public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(  nThreads, nThreads, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() );Copy the code

This is a fixed number of thread pools. When threads are idle, they are not reclaimed unless the pool is closed.

When all threads are active, new tasks wait until a thread is free.

Because FixedThreadPool has only core threads and these core threads are not recycled, this means that it can respond to requests from outside the FixedThreadPool more quickly.

As you can see from the constructor,FixedThreadPool has only core threads and has a timeout of 0(i.e., no timeout), so it will not be recycled.


2.CacheThreadPool

SynchronousQueue The queue is SynchronousQueue, and there is no capacity in the queue. ExecutorService newCacheThreadPool(){return new ThreadPoolExecutor( 0,Integer.MAX_VALUE, 60L,TimeUnit.SECONDS, new SynchronousQueue<Runnable>() ); }Copy the code

It is a thread pool with an indefinite number of threads, only non-core threads, and the maximum number of threads is integer.max_value (i.e., the pool can have an infinite number of threads).

When all threads in the thread pool are active, the pool creates new threads to handle new tasks, otherwise it reuses idle threads.

Note that the queue that stores tasks in this thread pool is the SynchronousQueue queue, which can be understood as an unstorable queue to which tasks are added only if they can be fetched.

Looking at the overall CacheThreadPool features:

(1) More suitable for performing a large number of less time-consuming tasks.

(2) When the entire thread is idle, threads in the thread pool timeout and are stopped, and the CacheThreadPool occupies almost no system resources.


3.ScheduledThreadPool

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSzie) { return new ScheduledThreadPoolExecutor(corePoolSzie); } / / core number of threads is fixed, non-core thread is infinite, and non-core threads have 10 s of free survival time public ScheduledThreadPoolExecutor (int corePoolSize) {super (corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }Copy the code

It has a fixed number of core threads, while there is no limit to the number of non-core threads, and non-core threads are immediately reclaimed when idle.

Thread pools such as ScheduThreadPool are mainly used to execute scheduled tasks and repetitive tasks with fixed cycles.

DelayedWorkQueue (DelayedWorkQueue) is a DelayedQueue (DelayedWorkQueue). The DelayedWorkQueue is a DelayedQueue (DelayedWorkQueue).

4.SingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() { return Executors.newSingleThreadExecutor(); } // Features: ExecutorService newSingleThreadExecutor() {return new. ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }Copy the code

This type of thread pool has only one core thread inside it, which ensures that all tasks are executed sequentially in the same thread.

The point of SingleThreadExecutor is to unify all external tasks into one thread, so that there is no need to deal with thread synchronization between these tasks.


Reference Documents:

2. 1. The android development artistic exploration ThreadPoolExecutor parsing - http://blog.csdn.net/wenhuayuzhihui/article/details/51377174 3 main source research. Understanding of Java thread interrupts (interrupt) http://blog.csdn.net/canot/article/details/51087772Copy the code