Why use thread pool?
- 1. Creating / destroying threads is accompanied by system overhead. Creating / destroying threads too frequently will greatly affect the processing efficiency
- 2. There are too many concurrent threads, which preempt system resources, resulting in blocking
- 3. Some simple management of threads
In Java, the concept of thread pool is the interface of Executor, which is specifically implemented as the ThreadPoolExecutor class. By learning the thread pool in Java, you can directly learn its configuration of thread pool, that is, the configuration of parameters of ThreadPoolExecutor constructor
1, ThreadPoolExecutor provides four constructors
//Five parameter constructor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) //Six parameter constructor - 1 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) //Six parameter constructor - 2 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) //Seven parameter constructor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
The parameters are explained below:
- int corePoolSize: the maximum number of core threads in the thread pool
Core thread: when creating a new thread in the thread pool, if the current total number of threads is less than corePoolSize, the new thread is a core thread. If it exceeds corePoolSize, the new thread is a non core thread. By default, the core thread will always survive in the thread pool, even if the core thread does nothing (idle state).
If the attribute allowCoreThreadTimeOut of ThreadPoolExecutor is specified as true, the core thread will be destroyed if it does not work (idle state) for a certain time (the duration is determined by the following parameters).
- int maximumPoolSize: the maximum number of threads in the thread pool
Total number of threads = number of core threads + number of non core threads.
- long keepAliveTime: the idle timeout length of non core threads in the thread pool
A non core thread will be destroyed if it does not work (idle state) for more than the time set by this parameter. If allowCoreThreadTimeOut = true, it will act on the core thread.
- TimeUnit unit: the unit of keepAliveTime
TimeUnit is an enumeration type that includes:
NANOSECONDS: 1 microsecond = 1 microsecond / 1000
MICROSECONDS: 1 microsecond = 1 millisecond / 1000
MILLISECONDS: 1ms = 1s / 1000
SECONDS: SECONDS
MINUTES: MINUTES
HOURS: HOURS
DAYS: DAYS
- BlockingQueue workQueue: the task queue in the thread pool: maintains the Runnable object waiting for execution
When all core threads are working, the newly added task will be added to the queue for processing. If the queue is full, a new non core thread will be created to execute the task.
Common workQueue types:
-
SynchronousQueue: when the queue receives a task, it will directly submit it to the thread for processing without retaining it. What if all threads are working? Then create a new thread to handle this task! Therefore, in order to ensure that there is no error that < the number of threads reaches maximumPoolSize and cannot create new threads >, when using this type of queue, maximumPoolSize is generally specified as integer MAX_ Value is infinite
-
LinkedBlockingQueue: when the queue receives a task, if the current number of threads is less than the number of core threads, a new thread (core thread) will be created to process the task; If the current number of threads is equal to the number of core threads, it will enter the queue and wait. Since there is no maximum limit for this queue, that is, all tasks exceeding the number of core threads will be added to the queue, which leads to the invalidation of the setting of maximumPoolSize, because the number of bus processes will never exceed corePoolSize
-
ArrayBlockingQueue: it can limit the length of the queue. When receiving a task, if the value of corePoolSize is not reached, a new thread (core thread) will execute the task. If it is reached, it will wait in the queue. If the queue is full, a new thread (non core thread) will execute the task. If the total number of threads reaches maximumPoolSize and the queue is full, an error will occur
-
DelayQueue: the elements in the queue must implement the Delayed interface, which means that the tasks you pass in must implement the Delayed interface first. When receiving a task, the queue first enters the queue, and the task will not be executed until the specified delay time is reached
-
ThreadFactory threadFactory: the way to create a thread. This is an interface. You need to implement its Thread newThread(Runnable r) method when you create a new thread. It is generally not used.
-
RejectedExecutionHandler handler: this thing is dedicated to throwing exceptions. For example, if the two errors mentioned above occur, this handler will throw exceptions, which is useless at all.
2, Add task to ThreadPoolExecutor
How do we know about a ThreadPoolExecutor? We probably know what the parameters are. But when I finish new, how can I submit a task to be executed to the thread pool?
ThreadPoolExecutor.execute(Runnable command)
Through ThreadPoolExecutor The execute (runnable command) method adds a task to the thread pool.
3, Policy for ThreadPoolExecutor
Here is a summary. When a task is added to the thread pool, the execution strategy:
- 1. If the number of threads does not reach the corePoolSize, create a new thread (core thread) to execute the task
- 2. When the number of threads reaches corePools, move the task into the queue and wait
- 3. The queue is full. Create a new thread (non core thread) to execute the task
- 4. When the queue is full and the number of bus processes reaches maximumPoolSize, an exception will be thrown by (RejectedExecutionHandler)
+++++++++++++++++++++++++++I am the dividing line++++++++++++++++++++++++++++
There are four common thread pools:
If you want to implement the four thread pools directly through Java thread executor or thread pool, you don't want to configure them directly.
1. Cacheable thread pool (cachedthreadpool)
Source code:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
According to the source code:
- There are no core threads in this thread pool, and the number of threads is unlimited.
- When creating a task, if there is an idle thread, the idle thread will be reused. If there is no idle thread, a new thread will be created.
- Threads that are not working (idle) will be destroyed if they do not work for more than 60S.
Creation method:
ExecutorService mCachedThreadPool = Executors.newCachedThreadPool();
Usage:
//Start downloading private void startDownload(final ProgressBar progressBar, final int i) { mCachedThreadPool.execute(new Runnable() { @Override public void run() { int p = 0; progressBar.setMax(10);//10 seconds per download task while (p < 10) { p++; progressBar.setProgress(p); Bundle bundle = new Bundle(); Message message = new Message(); bundle.putInt("p", p); //Use handler to display the name of the current thread in textview bundle.putString("ThreadName", Thread.currentThread().getName()); message.what = i; message.setData(bundle); mHandler.sendMessage(message); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); }
2. Fixed length thread pool
Source code:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
According to the source code:
- The maximum number of threads in the thread pool is equal to the number of core threads, so by default, the threads in the thread pool will not be destroyed due to idle timeout.
- If the current number of threads is less than the number of core threads, and there are idle threads that submit tasks, the previous idle threads will not be reused, and a new thread will be created to execute the task. If the current number of tasks executed is greater than the number of core threads, the greater part will enter the queue and wait. Waiting for idle threads to perform this task.
Creation method:
//Nthreads = > maximum number of threads, i.e. maximumPoolSize ExecutorService mFixedThreadPool= Executors.newFixedThreadPool(int nThreads); //Threadfactory = > the method of creating threads is rarely used ExecutorService mFixedThreadPool= Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
Usage:
private void startDownload(final ProgressBar progressBar, final int i) { mFixedThreadPool.execute(new Runnable() { @Override public void run() { //.... Logic code self control } }); }
3.SingleThreadPool
Source code:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
According to the source code:
- There is and only one worker thread executing the task
- All tasks are executed in the specified order, that is, follow the queue in and out rules
Creation method:
ExecutorService mSingleThreadPool = Executors.newSingleThreadPool();
The usage is the same as above.
4.ScheduledThreadPool
Source code:
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()); }
According to the source code:
DEFAULT_KEEPALIVE_MILLIS is the default 10L, here is 10 seconds. This thread pool is a bit like a combination of CachedThreadPool and FixedThreadPool.
- Not only the number of core threads is set, but also the maximum number of threads is integer MAX_ VALUE.
- This thread pool is the only thread pool with delayed execution and periodic execution tasks among the above four.
establish:
//Nthreads = > maximum number of threads, i.e. maximumPoolSize ExecutorService mScheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
The general task execution methods are similar to those above. We mainly look at the methods of delayed task execution and periodic task execution.
//It means to start our task in 3 seconds. mScheduledThreadPool.schedule(new Runnable() { @Override public void run() { //.... } }, 3, TimeUnit.SECONDS);
//Execute the task after a delay of 3 seconds. From the time when the task starts to be executed, it will be executed every 7 seconds, no matter how long it takes to execute the task. mScheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { //.... } },3, 7, TimeUnit.SECONDS);
/**Execute the task after a delay of 3 seconds, start timing from the time when the task is completed, and then execute it after 7 seconds, *Wait for 7 seconds after completion, that is to say, the time point of circular execution task here is *From when the last task was completed. */ mScheduledThreadPool.scheduleWithFixedDelay(new Runnable() { @Override public void run() { //.... } },3, 7, TimeUnit.SECONDS);
The above are the four commonly used thread pools and their implementation principles.
Reference article: https://www.cnblogs.com/williamjie/p/9485723.html