2013-07-27 2 views
7

Если я выполняю длительные задачи, Executor никогда не запускает новые потоки, если первая задача не завершена. Может кто-то, пожалуйста, помогите мне понять, почему и как я могу это исправить?Исполнитель не выполняет задачи, как ожидалось

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.LinkedBlockingQueue; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 

import org.junit.Test; 

public class TestExecutor { 

    @Test 
    public void test() throws InterruptedException { 
     ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 10, 
       100000, TimeUnit.MILLISECONDS, 
       new LinkedBlockingQueue<Runnable>()); 

     for (int i = 0; i < 20; i++) { 
      checkTasksExecutorService.execute(new Runnable() { 

       public void run(){ 
        try { 
         System.out.println(Thread.currentThread().getName() + " running!"); 
         Thread.sleep(10000); 
        } catch (Exception e) { 
        } 

       } 
      }); 
     } 

     Thread.sleep(1000000); 
    } 
} 

ответ

3

Такое поведение обусловлено логикой внутри ThreadPoolExecutor, где новые темы добавляются, если есть неспособность предложить задачу в очереди. Ваша очередь не ограничена, поэтому она эффективно означает, что мы никогда не будем расти выше основного размера пула и до максимального размера пула.

Попробуйте этот пример, чтобы увидеть разницу:

ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 10, 
       100000, TimeUnit.MILLISECONDS, 
       new SynchronousQueue<Runnable>()); 

     for (int i = 0; i < 10; i++) { 
      checkTasksExecutorService.execute(new Runnable() { 

       public void run() { 
        try { 
         System.out.println(Thread.currentThread().getName() + " running!"); 
         Thread.sleep(1000); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 

       } 
      }); 
     } 

     //Thread.sleep(1000000); //instead this use following 

//stop accepting new tasks 
     checkTasksExecutorService.shutdown(); 

while (!checkTasksExecutorService.isTerminated()) { 
      Thread.sleep(100); 
     } 
3

Javadoc из ExecutorService.execute() говорит:

Выполняет заданную команду в какой-то момент в будущем. Команда может выполняться в новом потоке, в объединенном потоке или в вызывающем потоке, по усмотрению реализации Исполнителя.

Это подкреплено Javadoc для ThreadPoolExecutor.execute(), в котором говорится:

Задача может выполняться в новом потоке или в существующем потоке.

Но причина объясняется в источнике комментарии для ThreadPoolExecutor.execute(), который говорит:

Если задача может быть успешно поставлены в очередь, то мы сделали

и бит позднее

Если мы не можем стоять в очередь задачи, то мы пытаемся добавить новый поток

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

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

+0

Вы должны были смотреть на 'ThreadPoolExecutor' класс Javadoc :) –

+0

@MarkoTopolnik javadoc не держит ответ! См. Мои правки – Bohemian

+0

Как вы оцениваете? Вы видели мою цитату? Он точно предсказывает, что произойдет, и что изменится, чтобы исправить это. –

4

Это решается в документации:

Когда новая задача представляется в методе execute(java.lang.Runnable), и меньше, чем corePoolSize нити работает, новый поток создается, чтобы обработать запрос, даже если другие потоки рабочих простаивают. Если существует более corePoolSize, но менее maximumPoolSize тем работает, новый поток будет создан , только если очередь заполнена.

Таким образом, чтобы достичь поведения, которое вы хотите, либо увеличить corePoolSize или дать на службу Исполнителя не расширяемую очередь, как это:

ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 20, 
    100000, TimeUnit.MILLISECONDS, 
    new SynchronousQueue<Runnable>()); 
Смежные вопросы