Что такое основные потоки в ThreadPoolExecutor?

Я смотрел на класс ThreadPoolExecutor и обнаружил, что он позволяет указать максимальный размер пула и размер основного пула.

Я немного понимаю, когда менять размеры ядра и максимального пула на основе ответа здесь: Когда целесообразно указывать отдельные ядра и максимальные размеры пула в ThreadPoolExecutor?

Тем не менее, я хотел бы знать, что это за «основные потоки». Я всегда получаю 0, когда использую метод getCorePoolSize() для ThreadPoolExecutor

SSCCE здесь:

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

    }
}

person An SO User    schedule 09.11.2013    source источник


Ответы (2)


основные потоки - это минимум, который всегда работает на тот случай, если вы хотите передать ему задачу. Кэшированный пул по умолчанию имеет ядро ​​0, как и следовало ожидать.

Для фиксированного пула потоков ядро ​​и максимум одинаковы, то есть независимо от того, для чего вы устанавливаете фиксированный размер.

person Peter Lawrey    schedule 09.11.2013
comment
Итак, если в cached thread pool я изменю количество основных потоков, то это похоже на fixed thread pool, эти ребята всегда будут там. Однако потоки, не используемые более минуты, будут отброшены. Чистый результат сочетает в себе преимущества как кэшированного, так и фиксированного пула потоков. Правильно ? - person An SO User; 09.11.2013
comment
В конечном итоге вы создаете пул с несколькими потоками, которые всегда находятся в режиме ожидания, а другие потоки создаются по мере необходимости. Бездействующие потоки не будут потреблять память, так как ресурсы, которые они занимают, будут освобождены. - person An SO User; 09.11.2013

core threads — это просто стандартные потоки, но они всегда будут поддерживаться в пуле, а затем другие неосновные потоки закончат свою жизнь после завершения метода run().

Но как эти core threads могли быть всегда живы? Это потому, что они всегда ждут выполнения задачи из workQueue общего доступа в пуле. По умолчанию workQueue является BlockingQueue, его метод take() будет блокировать текущий поток на неопределенное время, пока задача не станет доступной.

Здесь наступает ключевой момент, какие потоки станут core threads? Они могут быть не первыми или последними, а теми (corePoolSize), которые существуют дольше всего. Легче понять из кода.

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

То, что я только что сказал выше, основано на allowCoreThreadTimeOut, установленном как false.

На самом деле, я предпочитаю называть core threads как core workers.

person Echo Yuan    schedule 05.06.2017