* This article has been published exclusively by guolin_blog, an official wechat account
Why thread pools
-
Creating/destroying threads comes with overhead, and creating/destroying threads too frequently can greatly affect processing efficiency
Such as:
Remember time T1 for thread creation, time T2 for task execution, and time T3 for thread destruction
If T1+T3>T2, then it is not cost-effective to start a thread to perform the task!
As it happens, thread pools cache threads and can use existing idle threads to perform new tasks, avoiding the overhead of T1+T3
-
Too many concurrent threads seize system resources and block
We know that threads can share system resources, and if too many threads are executing at the same time, the system may not have enough resources and block
Using thread pool can effectively control the maximum number of concurrent threads to avoid the above problems
-
Do some simple thread management
For example, delay execution and periodic cyclic execution
Thread pools can be used to do this
The thread pool ThreadPoolExecutor
Since Android thread pools come from Java, studying Android thread pools can also be said to be studying Java thread pools
In Java, the concept of a thread pool is the Executor interface, which is implemented as the ThreadPoolExecutor class
The configuration of the thread pool is the configuration of the parameters of the ThreadPoolExecutor constructor, and since these parameters are so important, let’s take a look at the parameters of the constructor
ThreadPoolExecutor provides four constructors
Public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, Public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, Public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)Copy the code
I know you’re as freaked out by these constructors as I am, but there are only seven types, and it’s almost as easy to understand as there are seven days a week, and two weekends a week, when there are only five! Trust me, I’m good at bullshit
-
Int corePoolSize => Maximum number of core threads in the thread pool
Core thread:
When a thread pool creates a new thread, if the current number of threads is smaller than corePoolSize, it creates a core thread; if it exceeds corePoolSize, it creates a non-core thread
A core thread is always alive in the thread pool by default, even if the core thread is idle.
If the allowCoreThreadTimeOut property of ThreadPoolExecutor is set to true, the core thread will be destroyed if it is idle for more than a certain amount of time
It is easy to understand that in normal circumstances I will support you if you do not work, because I am always useful to you, but sometimes special circumstances (such as I can no longer support myself), if you do not work, I will kill you
-
int maximumPoolSize
Maximum number of threads in this thread pool
Total threads = number of core threads + number of non-core threads. Core threads were explained above, but here are non-core threads:
Threads that are not core threads (calm down, put the knife down…) , as explained above
-
long keepAliveTime
Non-core thread idle timeout in this thread pool
A non-core thread that has been inactive for longer than this parameter is destroyed
AllowCoreThreadTimeOut = true applies to the core thread
-
TimeUnit unit
The unit of keepAliveTime, TimeUnit is an enumeration type that includes:
- NANOSECONDS: 1 micromillisecond = 1 microsecond / 1000
- MICROSECONDS: 1 microsecond = 1 millisecond / 1000
- MILLISECONDS: 1 millisecond = 1 second /1000
- SECONDS: SECONDS
- MINUTES: points
- HOURS: HOURS
- DAYS: day
-
BlockingQueue workQueue
The task queue in this thread pool: maintains Runnable objects waiting to be executed
When all the core threads are working, new tasks are added to the queue for processing, and if the queue is full, a new non-core thread is created to execute the task
Common workQueue types:
-
SynchronousQueue: When a task is received, it is submitted directly to the thread instead of being retained. What if all threads are working? Create a new thread to handle the task! Therefore, maximumPoolSize is usually specified as integer. MAX_VALUE, or infinite, when using this type of queue to ensure that no new thread can be created when the number of threads reaches maximumPoolSize
-
LinkedBlockingQueue: When this queue receives a task, if the number of current threads is smaller than the number of core threads, a new thread (core thread) will process the task. If the number of current threads is equal to the number of core threads, the queue is queued. Since there is no maximum limit on this queue, any task that exceeds the number of core threads will be added to the queue, which invalidates maximumPoolSize because the total number of threads will never exceed corePoolSize
-
ArrayBlockingQueue: If the queue is full, a new thread (non-core thread) will execute the task. If the queue is full, a new thread (non-core thread) will execute the task. If the total number of threads reaches maximumPoolSize, a new thread will execute the task. And the queue is full, an error occurs
-
DelayQueue: The elements in the queue must implement the Delayed interface, which means that the task you sent in must implement the Delayed interface first. When the queue receives a task, it joins the queue first. The task will be executed only after the specified delay time is reached
-
-
ThreadFactory threadFactory
The way to create a Thread, this is an interface, and when you create it you need to implement its Thread newThread(Runnable R) method, which is usually not used, this is Saturday, off
But I will say this anyway (put the gun down…)
AsyncTask encapsulates a thread pool. ThreadFactory AsyncTask threadFactory AsyncTask threadFactory AsyncTask threadFactory AsyncTask threadFactory
new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread new Thread(Runnable r) { return new Thread(r,"AsyncTask #" + mCount.getAndIncrement()); }}Copy the code
That simple? Just give the thread a name, right? ! Yeah, so it’s Saturday, so forget it, even though I forced you to watch it…
-
RejectedExecutionHandler handler
This thing is specially designed to throw exceptions. For example, if the above two errors occur, this handler will throw an exception, and you don’t specify that it has a default
What kind of tricks can an exception throw? So I don’t care about this Sunday. I don’t need it
When creating a new thread pool, you typically only use the five-parameter constructor.
Add tasks to ThreadPoolExecutor
ThreadPoolExecutor = ThreadPoolExecutor = ThreadPoolExecutor = ThreadPoolExecutor = ThreadPoolExecutor = ThreadPoolExecutor;
Through the ThreadPoolExecutor. Execute (Runnable command) method to add a thread pool with a task
The strategy of ThreadPoolExecutor
The policy that ThreadPoolExecutor executes when a task is added to the thread pool is summarized as follows:
- If the number of threads does not reach corePoolSize, a new thread (core thread) is created to execute the task
- When the number of threads reaches corePools, the task is moved to the queue to wait
- The queue is full and a new thread (non-core thread) executes the task
- If the queue is full and the total number of threads reaches maximumPoolSize, an exception will be thrown by the previous Sunday (RejectedExecutionHandler)
There are four common thread pools
If you don’t want to write your own thread pool, you can check below to see if there is one that meets your requirements. If there is one, you can just use it. If not, you can write your own thread pool
Java provides four thread pools via Executors, which are implemented by directly or indirectly configuring the Parameters of ThreadPoolExecutor. / / Thread pool constructors.
Come and go:
CachedThreadPool()
Cacheable thread pool:
- Unlimited number of threads
- If there are idle threads, reuse idle threads. If there are no idle threads, create a new thread
- Certain programs reduce frequent creation/destruction of threads and reduce system overhead
Create method:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
Source:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}Copy the code
Through my above flowing eloquence and chattering on the description of various parameters, this source you will certainly understand at a glance, do not want to think (the following three same)
FixedThreadPool()
Fixed length thread pool:
- Maximum number of concurrent threads that can be controlled (the number of threads executing simultaneously)
- The exceeded thread will wait in the queue
Create method:
/ / nThreads = > maximum number of threads that maximumPoolSize ExecutorService fixedThreadPool = Executors. NewFixedThreadPool (int nThreads); //threadFactory => this is the Saturday I told you to ignore it! Do you still look! ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);Copy the code
Source:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}Copy the code
2 parameter constructor source, I don’t have to post you also know he put Saturday in which position! So I won’t post it, save space for my bullshit
ScheduledThreadPool()
Fixed length thread pool:
- Supports scheduled and periodic task execution.
Create method:
/ / nThreads = > maximum number of threads that maximumPoolSize ExecutorService scheduledThreadPool = Executors. NewScheduledThreadPool (int corePoolSize);Copy the code
Source:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//ScheduledThreadPoolExecutor():
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}Copy the code
SingleThreadExecutor()
Single threaded thread pool:
- One and only one worker thread executes the task
- All tasks are executed in the specified order, that is, following the queue entry and exit rules
Create method:
ExecutorService singleThreadPool = Executors.newSingleThreadPool();
Source:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}Copy the code
There is also a Executors. NewSingleThreadScheduledExecutor () combined with 3 and 4, not introduced, basic need not.
conclusion
Wall crack suggested that you read this article must actually start to knock again are verified again, so as to have a good grasp of knowledge
Doing is always the best way to learn!
end
- For more content please visit my homepage or my blog
- If my article really helped you, please don’t forget to click “♡” at the end of the following to make it “❤”
- As a rookie, it is inevitable that I do not understand many places well. If there is any mistake in the text, please connect (bu) directly to (ma) out (wo).
- Writing is not easy!