2013-11-09 3 views
3

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

Я понимаю, немного, о том, когда изменить основные и максимальный размер пула на основе ответа здесь: When is specifying separate core and maximum pool sizes in ThreadPoolExecutor a good idea?

Однако, я хотел бы знать, каковы эти «основные темы». Я всегда получаю 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 

    } 
} 

ответ

5

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

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

+0

ОК, поэтому, если в «кэшированном пуле потоков» я меняю количество основных потоков, схожих с «фиксированным пулом потоков», эти ребята всегда будут там. Тем не менее, нити, не используемые более минуты, будут отброшены. Чистый результат объединяет преимущества как кэшированного, так и фиксированного пула потоков. Правильно ? –

+0

Вы создаете пул, в котором есть несколько потоков, которые всегда находятся в режиме ожидания, и при необходимости создаются другие потоки. Неработающие потоки не будут потреблять память, поскольку ресурсы, которые они берут, будут освобождены. –

0

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.

Смежные вопросы