Three Cache Queues for Thread Pool

Posted by Prine on Fri, 10 May 2019 01:12:03 +0200

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");
        }
    }
}

 

Topics: Java