The most recommended asynchronous programming tool in Android development is Kotlin coroutine. Before introducing the Kotlin coroutine mechanism, in addition to responsive extension (RxJava) as an asynchronous programming tool, threads and thread pools in the Java API are the most important asynchronous programming methods. For the implementation of Kotlin coroutines on the Android platform, the thread pool is still used as the carrier of task execution, so the simple understanding of Kotlin coroutines on the Android platform is a highly encapsulation of thread pools.
(10).asCoroutineDispatcher() ()
Therefore, we first understand how Java thread pools run, and then deeply understand how Kotlin coroutines are implemented.
From Thread to Executor
Thread creation is done through the Thread class, and pooling is done in order to reuse threads, and a thread pool is available. Thread pools bring two obvious advantages:
- Reduce the overhead of repetitive creation threads
- Decouple tasks from thread management
The Executor interface is the embodiment of the second point. Its execute method is used to execute tasks, and does not have to do with what the carrier of the task is, and whether there are any threads created. The ThreadPoolExecutor implementation class is the thread pool implementation of this task executor.
ThreadPoolExecutor task addition and thread reuse
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = (); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = (); }//1 if (isRunning(c) && (command)) { int recheck = (); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); }//2 else if (!addWorker(command, false)) reject(command);//3 }
Check the execute method to understand how it runs:
- When the number of threads is less than corePoolSize, create a thread and execute a task;
- If the task is not added through step 1, then join the queue workQueue; (The main logic is in the conditional judgment of if, and the logic within if handles the rollback or supplementary creation thread of joining under some exceptions)
- If the task is not queued, a thread is still created (upper limit is maximumPoolSize) and the task is executed, and a rejection policy is executed if it fails.
boolean addWorker(Runnable firstTask, boolean core)
It is the method of creating threads. The second parameter in the method represents the boundary of corePoolSize or maximumPoolSize. The details of the other threads created in the method are not thoroughly investigated. But you should pay attention to the thread's encapsulated class Worker. The addWorker method calls the start method of the encapsulated thread in the Worker to execute the Worker run method. We simplify the runWorker in the run method as follows:
void runWorker(Worker w) { Runnable task = ; = null; while (task != null || (task = getTask()) != null) { (); } }
It can be found that after the initial task is executed, the task execution is continuously obtained through the getTask method to realize thread reuse, rather than destroying the thread after only one task is executed.
Also, check the simplified getTask method as follows:
private Runnable getTask() { boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; try { Runnable r = timed ? (keepAliveTime, ) : (); if (r != null) return r; } catch (InterruptedException retry) { } }
Is the task taken from the blocking queue workQueue, and based on whether the configuration allowsCoreThreadTimeOut and the number of threads are greater than corePoolSize, we decide whether to use the BlockingQueue<Runable> task method poll with timeout, or take the blocking task method to achieve timely destruction of threads or blocking threads when the task list is empty.
Looking back at the construction method of ThreadPoolExecutor:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
We can clearly understand the meaning of each parameter and how it affects the reuse of threads in the thread pool.
This is the end of this article about how Java thread pool runs. For more related Java thread pool content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!