Executors.newCacheThreadPool Example

0

In this article we are looking into one of the factory method of Executors called newCachedThreadPool. This is useful when you want to create a thread pool that allows us to add as many worker threads as needed, but should reuse a previously constructed thread if available.

Executors.newCachedThreadPool(threadFactory)

This internally creates ThreadPoolExecutor object passing the required attributes that tweak the behaviour based on our need. The attributes are the corePoolSize which is set to 0, maxPoolSize set to the maximum integer value, worker’s thread alive time set to one minute and SynchronousQueue instance passed as task queue.

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue(),
                                      threadFactory)

The core pool size is 0 which means there is no limit on the number of worker threads. The new worker added will run the first task assigned, and then will poll the queue for any new task to show up before terminating.  If there is no new task, after a minute, the work thread will stop polling and terminate.

Thus whenever we submit a new task it will first try to use an existing worker if available else a new worker is created. Below is a rough flow diagram.

ThreadPoolExecutorExampleUsingSynQueue:

package com.javarticles.threads;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadPoolExecutorExampleUsingSynQueue {

    public static void main(String[] args) {
        ThreadPoolExecutorExampleUsingSynQueue t = 
                new ThreadPoolExecutorExampleUsingSynQueue();
        t.createDefaultExecutor();
        t.submitTasks();
        t.submitTasks();
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.submitTasks();
    }    

    private void submitTasks() {
        Future<?>[] fs = new Future<?>[10];
        for (int i = 0; i < 10; i++) {
            fs[i]= es.submit(new Task(i, 200L));
        }   
        for (Future<?> f : fs ) {
            try {
                f.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

    public void createDefaultExecutor() {
        es = Executors.newCachedThreadPool(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable runnable) {
                String threadName = "Thread-" + threadCount.getAndIncrement();
                Thread thread = new Thread(runnable, threadName);
                thread.setDaemon(true);
                PrintUtils.print(String.format("Created thread[{%s}]: {%s}", threadName, thread));
                return thread;
            }
        });
    }
    
    private class Task implements Runnable {
        private int id;
        private long sleepMills;
        public Task(int i, long sleepMillis) {
            id = i;
            this.sleepMills = sleepMillis;
        }

        @Override
        public void run() {
            long t = System.currentTimeMillis();
            PrintUtils.print("Running task " + this);
            try {
                Thread.sleep(sleepMills);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            PrintUtils.print("Done task " + this + " took " + (System.currentTimeMillis() - t));
        }
        
        public String toString() {
            return "Task " + id;
        }
        
    }
    
    private ExecutorService es;
    private AtomicInteger threadCount = new AtomicInteger(1);

}

When we submit the tasks second time, some of the tasks are run by the existing workers. We than sleep for few seconds and the submit the third time. You can see below, the third time execution results in creation of new worker threads.

Output:

main:Created thread[{Thread-1}]: {Thread[Thread-1,5,main]}
main:Created thread[{Thread-2}]: {Thread[Thread-2,5,main]}
Thread-1:Running task Task 0
Thread-2:Running task Task 1
main:Created thread[{Thread-3}]: {Thread[Thread-3,5,main]}
main:Created thread[{Thread-4}]: {Thread[Thread-4,5,main]}
Thread-3:Running task Task 2
main:Created thread[{Thread-5}]: {Thread[Thread-5,5,main]}
Thread-4:Running task Task 3
main:Created thread[{Thread-6}]: {Thread[Thread-6,5,main]}
Thread-5:Running task Task 4
main:Created thread[{Thread-7}]: {Thread[Thread-7,5,main]}
Thread-6:Running task Task 5
main:Created thread[{Thread-8}]: {Thread[Thread-8,5,main]}
Thread-7:Running task Task 6
main:Created thread[{Thread-9}]: {Thread[Thread-9,5,main]}
Thread-8:Running task Task 7
Thread-9:Running task Task 8
main:Created thread[{Thread-10}]: {Thread[Thread-10,5,main]}
Thread-10:Running task Task 9
Thread-1:Done task Task 0 took 200
Thread-2:Done task Task 1 took 200
Thread-3:Done task Task 2 took 200
Thread-6:Done task Task 5 took 200
Thread-5:Done task Task 4 took 200
Thread-4:Done task Task 3 took 200
Thread-9:Done task Task 8 took 200
Thread-7:Done task Task 6 took 200
Thread-8:Done task Task 7 took 200
Thread-10:Done task Task 9 took 200
Thread-10:Running task Task 0
Thread-1:Running task Task 7
Thread-3:Running task Task 8
Thread-2:Running task Task 9
Thread-6:Running task Task 6
Thread-5:Running task Task 5
Thread-9:Running task Task 3
Thread-8:Running task Task 1
Thread-4:Running task Task 4
Thread-7:Running task Task 2
Thread-5:Done task Task 5 took 201
Thread-3:Done task Task 8 took 201
Thread-10:Done task Task 0 took 201
Thread-1:Done task Task 7 took 201
Thread-2:Done task Task 9 took 201
Thread-6:Done task Task 6 took 201
Thread-9:Done task Task 3 took 201
Thread-8:Done task Task 1 took 201
Thread-4:Done task Task 4 took 201
Thread-7:Done task Task 2 took 201
Thread-7:Running task Task 0
Thread-4:Running task Task 1
Thread-8:Running task Task 2
main:Created thread[{Thread-11}]: {Thread[Thread-11,5,main]}
Thread-11:Running task Task 3
main:Created thread[{Thread-12}]: {Thread[Thread-12,5,main]}
main:Created thread[{Thread-13}]: {Thread[Thread-13,5,main]}
Thread-12:Running task Task 4
main:Created thread[{Thread-14}]: {Thread[Thread-14,5,main]}
Thread-13:Running task Task 5
main:Created thread[{Thread-15}]: {Thread[Thread-15,5,main]}
Thread-14:Running task Task 6
main:Created thread[{Thread-16}]: {Thread[Thread-16,5,main]}
Thread-15:Running task Task 7
main:Created thread[{Thread-17}]: {Thread[Thread-17,5,main]}
Thread-16:Running task Task 8
Thread-17:Running task Task 9
Thread-4:Done task Task 1 took 201
Thread-7:Done task Task 0 took 201
Thread-11:Done task Task 3 took 200
Thread-8:Done task Task 2 took 201
Thread-17:Done task Task 9 took 200
Thread-12:Done task Task 4 took 201
Thread-15:Done task Task 7 took 200
Thread-13:Done task Task 5 took 201
Thread-16:Done task Task 8 took 200
Thread-14:Done task Task 6 took 201

Download the source code

This was about creating new thread cache pool using Executors factory method newCachedThreadPool().

You can download the source code here: javaExecutorServiceCachedPoolExample.zip
Share.

Comments are closed.