An SO User
An SO User

Reputation: 24998

What are core threads in a ThreadPoolExecutor?

I was looking at the ThreadPoolExecutor class and I found that it allows to specify the maximum pool size and the core pool size.

I understand, a little, about when to change the core and maximum pool sizes based on the answer here: When is specifying separate core and maximum pool sizes in ThreadPoolExecutor a good idea?

However, I would like to know what are these 'core threads'. I always get 0 when I use the getCorePoolSize() method of a ThreadPoolExecutor

SSCCE here:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

public class PoolSize {
    public static void main(String[] args) {
        // Create a cached thread pool
        ExecutorService cachedPool = Executors.newCachedThreadPool();
        // Cast the object to its class type
        ThreadPoolExecutor pool = (ThreadPoolExecutor) cachedPool;

        // Create a Callable object of anonymous class
        Callable<String> aCallable = new Callable<String>(){
            String result = "Callable done !";
            @Override
            public String call() throws Exception {
                // Print a value
                System.out.println("Callable at work !");
                // Sleep for 5 sec
                Thread.sleep(0);
                return result;
            }
        };

        // Create a Runnable object of anonymous class
        Runnable aRunnable = new Runnable(){
            @Override
            public void run() {
                try {
                    // Print a value
                    System.out.println("Runnable at work !");
                    // Sleep for 5 sec
                    Thread.sleep(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        // Submit the two tasks for execution
        Future<String> callableFuture = cachedPool.submit(aCallable);
        Future<?> runnableFuture = cachedPool.submit(aRunnable);

        System.out.println("Core threads: " + pool.getCorePoolSize());
        System.out.println("Largest number of simultaneous executions: " 
                                            + pool.getLargestPoolSize());
        System.out.println("Maximum number of  allowed threads: " 
                                            + pool.getMaximumPoolSize());
        System.out.println("Current threads in the pool: " 
                                            + pool.getPoolSize());
        System.out.println("Currently executing threads: " 
                                            + pool.getTaskCount());

        pool.shutdown(); // shut down

    }
}

Upvotes: 3

Views: 3078

Answers (2)

Echo Yuan
Echo Yuan

Reputation: 11

The core threads are just standard threads but will be always kept alive in the pool, and then the other non-core threads will end their lives after the run() method finished.

But how could these core threads be always alive? That's because they are always waiting for taking a task from the workQueue shared within the pool. By default, the workQueue is a BlockingQueue, its take() method will block the current thread indefinitely until a task becomes available.

Here comes the key point, which threads will become the core threads? They may not be the first started ones or the last ones, but the ones(corePoolSize) that last the longest. Easier to understand from the code.

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            //------------- key code ------------------
            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            //------------- key code ------------------
            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

What I just said above is based on allowCoreThreadTimeOut set as false.

Actually, I prefer to call core threads as core workers.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533510

core threads is the minimum which is always running just in case you want to pass it a task. The cached pool by default has a core of 0 as you might expect.

For the fixed thread pool, the core and the maximum are the same i.e. whatever you set the fixed size to.

Upvotes: 5

Related Questions