Метод ThreadFactory newThread() вызывается только один раз для каждого вызова submit() в ThreadPoolExectutor

Я пытаюсь присвоить номер каждому из MyRunnable, отправленному ThreadPoolExecutor, но мне это не удалось.

Мой фрагмент кода:

import java.util.concurrent.*;

class SimpleThreadFactory implements ThreadFactory {
   String name;
   static int threadNo = 0;

   public SimpleThreadFactory (String name){
       this.name = name;
   }
   public Thread newThread(Runnable r) {
     ++threadNo;
     System.out.println("thread no:"+threadNo);
     return new Thread(r,name+":"+threadNo );
   }
   public static void main(String args[]){
        SimpleThreadFactory factory = new SimpleThreadFactory("Ravindra");
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1,5,10,TimeUnit.SECONDS,new ArrayBlockingQueue(100),factory);
        for ( int i=0; i < 10; i++){
            executor.submit(new MyRunnable());
        }
        executor.shutdown();
    }
 }

 class MyRunnable implements Runnable {
     public void run(){
         System.out.println("Runnable:"+Thread.currentThread().getName());
     }
 }

Мои ожидания:

executor.submit(new MyRunnable()); должен вызывать newThread в ThreadFactory для каждой отправки на исполнителя. Но на самом деле это произошло только один раз.

Выход:

thread no:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1

Почему submit() не создает новый поток для каждой отправленной задачи Runnable?

Как я могу назначить порядковый номер каждому MyRunnable, отправленному исполнителю?

заранее спасибо


person Ravindra babu    schedule 18.01.2016    source источник
comment
Вероятно, не было необходимости в более чем 1 потоке в пуле для обработки всех задач. В конце концов, для этого и существуют службы-исполнители.   -  person biziclop    schedule 18.01.2016
comment
Понял :) Что за простая ошибка с моей стороны? Я сопоставил Thread с Runnable Task и забыл, что ThreadFactory предназначен для потока ExecutorService.   -  person Ravindra babu    schedule 18.01.2016
comment
Я получил 5 потоков (макс. потоки), когда изменил код для отправки 1000 задач. @ biziclop: Ваш комментарий скорректировал мой мыслительный процесс за считанные секунды.   -  person Ravindra babu    schedule 18.01.2016


Ответы (4)


Проблема заключается во взаимодействии между CorePoolSize и очередью.

Из Javadoc

«Если запущены corePoolSize или несколько потоков, исполнитель всегда предпочитает ставить запрос в очередь, а не добавлять новый поток».

а также

«Если запущено больше потоков, чем corePoolSize, но меньше, чем maxPoolSize, новый поток будет создан только в том случае, если очередь заполнена».

Итак, в настоящее время ваши задачи ставятся в очередь до тех пор, пока в CorePoolSize не будет места (т.е. когда ваша текущая выполняемая задача завершится), поэтому в настоящее время вы никогда не используете более 1 потока.

person matt freake    schedule 18.01.2016


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

Для начала подсчитайте экземпляры исполняемых, а не потоков, в которых они выполняются: например, так ->

class MyRunnable implements Runnable{
    private static long _mySequenceCounter = 0; // Maybe use an AtomicLong?
    private final long mySeqNo;

    MyRunnable(){ mySeqNo = ++_mySequenceCounter; }

// Your other stuff here

}

Внутри метода запуска вы можете переименовать текущий поток, если этого достаточно для ваших требований. Или вы можете просто вывести исполняемый идентификатор и оставить имя потока. Это имеет то преимущество, что вы будете знать, какой поток был повторно использован для какой задачи ... если это имеет для вас какое-то значение.

Примечание. Вышеприведенный фрагмент предназначен только для того, чтобы изложить идею того, как выполнить ваше требование для определения задачи. Конечно, вы можете улучшить его, если вам нужна потокобезопасность (фрагмент может быть проблематичным, если MyRunnables создаются более чем в 1 потоке).

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

person Fildor    schedule 18.01.2016

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

person Alexandre Cartapanis    schedule 18.01.2016
comment
В этом случае я думаю, что он просто хочет протестировать Executor. - person Alexandre Cartapanis; 18.01.2016