Recently, looking at the thread pool of java, I have compared and studied the three caching queues in it. I feel that the results of my test are different from some knowledge points on the internet, so I hope someone can help me solve the puzzle.
Summary
queue | Simple explanation |
SynchrousQueue | Submission tasks are not saved, beyond direct corePoolSize tasks, and new threads are created directly to perform tasks until (corePoolSize + new threads) > maximumPoolSize. Either the core thread or the new thread. |
LinkedBlockingQueue | First in, first out, unbounded queue based on linked list. Beyond the direct corePoolSize task, it joins the queue until resources are exhausted, so maximumPoolSize does not work. |
ArrayBlockingQueue | Based on FIFO of arrays, when creating an array, you must specify the size beyond the number of direct corePoolSize tasks, then join the queue and only add the size set by the queue. The remaining tasks create threads until (core PoolSize + new threads)> maximum PoolSize. |
SynchrousQueue
Create a pool of corePoolSize 2 and maximumPoolSize 3. Perform six tasks. As I understand it, SynchrousQueue is a cached queue (based on the SynchrousQueue source code, you can see that isEmpty() is always true; size() always returns 0)
According to the parameter setting, only three tasks can be performed:
Two core threads perform two tasks. |
The third task is to create a thread to execute task 3. |
By the time the fourth task arrives, it has exceeded maximum Pool Size, so it refuses the task. (But there are some online claims that a task can be cached into a queue here. I don't quite understand this statement, and I hope someone can answer it.) |
The code for creating a thread pool is as follows:
/** * SynchronousQueue */ private static void syncQueue() { System.out.println("\n\n =======SynchronousQueue====== \n\n"); Executor executors = new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new RejectHandler()); execute(executors); }
The results are as follows: (as I expected)
1 is running... 4 is rejected ^^ //4 rejected 2 is running... 3 is running... 5 is rejected ^^ //5 rejected 6 is rejected ^^ //6 rejected 3 is end !!! 1 is end !!! 2 is end !!!
ArrayBlockingQueue
Create a pool of corePoolSize 2 and maximumPoolSize 3. Array BlockingQueue sets up two caching tasks. Perform six tasks. Array Blocking Queue is a bounded queue:
Tasks 1 and 2 are executed in the core thread. |
Tasks 3 and 4 are placed in the Array BlockingQueue cache queue and can only be placed in two (the size of Array BlockingQueue is set to 2); |
When Tasks 5 and 6 come in, Task 5 creates new threads to execute tasks, which has reached the maximum number of threads 3, so Task 6 refuses. |
When a thread finishes executing, task 3 and 4 are removed from the queue for execution. |
The code for creating a thread pool is as follows:
/** * ArrayBlockingQueue */ private static void arrayQueue() { System.out.println("\n\n =======ArrayBlockingQueue====== \n\n"); Executor executors = new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new RejectHandler()); execute(executors); }
The results are as follows.
1 is running... 2 is running... 6 is rejected ^^ //6 rejected 5 is running... //5 New thread execution 1 is end !!! 2 is end !!! 3 is running... //1 and 2 are executed before 3 and 4 are executed 4 is running... 5 is end !!!
LinkedBlockingQueue
Create a pool of corePoolSize 2 and maximumPoolSize 3. Unbounded queue. Similarly perform six tasks
Core threads execute tasks 1 and 2, and other tasks 3 to 6 are queued |
Execute 1 and 2, remove 3 and 4 from the queue |
Execute 3 and 4 and remove 5 and 6 from the queue |
/** * LinkedBlockingQueue */ private static void linkedQueue() { System.out.println("\n\n =======LinkedBlockingQueue====== \n\n"); Executor executors = new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new RejectHandler()); execute(executors); }
The results are as follows:
1 is running... 2 is running... //Intermediate thread dormancy 2 is end !!! //10 seconds before running 1 is end !!! 3 is running... //Tasks 3 and 4 will be implemented 4 is running... 4 is end !!! 3 is end !!! 6 is running... 5 is running... 5 is end !!! 6 is end !!!
summary
queue | Number of threads created | The maximum number of tasks that can be executed willingly (put into the cache queue and execution thread) | Number of caches available |
SynchrousQueue | maximumPoolSize | (Number of threads created by corePoolSize +)<=maximumPoolSize | nothing |
ArrayBlockingQueue | maximumPoolSize | (Number of threads created by corePoolSize +) (Add up to <=maximumPoolSize) +Number of caches set by Array BlockingQueue | Number of caches set by Array BlockingQueue |
LinkedBlockingQueue | corePoolSize | Unbounded Tasks of corePoolSize+LinkedBlockingQueue Cache | unbounded |
The overall code is as follows:
public static void main(String[] args) { queue(); } /*** * Perform different cache queues */ private static void queue() { syncQueue(); //arrayQueue(); //linkedQueue(); } /** * ArrayBlockingQueue */ private static void arrayQueue() { System.out.println("\n\n =======ArrayBlockingQueue====== \n\n"); Executor executors = new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new RejectHandler()); execute(executors); } /** * LinkedBlockingQueue */ private static void linkedQueue() { System.out.println("\n\n =======LinkedBlockingQueue====== \n\n"); Executor executors = new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new RejectHandler()); execute(executors); } /** * SynchronousQueue */ private static void syncQueue() { System.out.println("\n\n =======SynchronousQueue====== \n\n"); Executor executors = new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new RejectHandler()); execute(executors); } private static void execute(Executor executors) { executors.execute(new NameRunnable(1)); executors.execute(new NameRunnable(2)); executors.execute(new NameRunnable(3)); executors.execute(new NameRunnable(4)); executors.execute(new NameRunnable(5)); executors.execute(new NameRunnable(6)); } /*** * Create a named runnable object */ private static class NameRunnable implements Runnable { private int name; public NameRunnable(int name) { this.name = name; } public int getName() { return name; } @Override public void run() { System.out.println(name + " is running... "); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + " is end !!! "); } } /*** * Rejected Runable */ private static class RejectHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { NameRunnable name = (NameRunnable) r; System.out.print(name.getName() + " is rejected ^^\n"); } } }