Метод 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, представленных исполнителю?
заранее спасибо
4 ответа
Проблема заключается во взаимодействии между CorePoolSize и очередью.
От Javadoc
"Если corePoolSize или несколько потоков запущены, Исполнитель всегда предпочитает ставить запрос в очередь, а не добавлять новый поток".
а также
"Если запущено больше потоков corePoolSize, но меньше MaximumPoolSize, новый поток будет создан, только если очередь заполнена".
Таким образом, в настоящее время ваши задачи помещаются в очередь до тех пор, пока в CorePoolSize не останется места (то есть, когда завершится текущая выполняемая задача), поэтому в настоящее время вы никогда не используете более 1 потока.
Увидеть ThreadPoolExecutor
JavaDoc под Core и максимальные размеры пула
Когда в метод execute передается новая задача (java.lang.Runnable), .... Если выполняется больше чем corePoolSize, но меньше чем MaximumPoolSize, новый поток будет создан, только если очередь заполнена.
Чтобы заставить ваш код создавать больше потоков, я изменил этот бит:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
// Core pool size
5,
// Max pool size
5,
// Resize time
1,
// Resize time units
TimeUnit.MILLISECONDS,
// Queue of runnables - I CHANGED THIS TO 10
new ArrayBlockingQueue(10),
// Factory to use for threads.
factory);
for (int i = 0; i < 100; i++) {
executor.submit(new MyRunnable());
}
Другие ответы объясняют, почему не было более одной темы. Мое предложение о том, как добиться того, чего вы на самом деле хотели, заключается в следующем:
Для начала подсчитайте количество экземпляров работоспособного объекта, а не потоков, в которых они запущены: например, вот так ->
class MyRunnable implements Runnable{
private static long _mySequenceCounter = 0; // Maybe use an AtomicLong?
private final long mySeqNo;
MyRunnable(){ mySeqNo = ++_mySequenceCounter; }
// Your other stuff here
}
Внутри run-method вы можете переименовать текущий поток, если этого достаточно для вашего требования. Или вы можете просто вывести работающий идентификатор и оставить имя потока. Преимущество этого в том, что вы будете знать, какой поток был повторно использован для какой задачи... если это имеет какое-то значение для вас.
Примечание. Выше приведен фрагмент кода, в котором изложена идея о том, как удовлетворить ваши требования для определения задачи. Конечно, вы можете улучшить его, если вам нужна безопасность потоков (фрагмент может быть проблематичным, если MyRunnables
создаются более чем в 1 потоке).
long
должно дать вам довольно много порядковых номеров, но имейте в виду, что даже длинный перевернется в какой-то момент. Так что вы можете решить эту проблему, если ваше приложение работает очень долго и имеет высокую частоту новых MyRunnable
s.
Попробуйте добавить сон в ваш метод run: здесь время выполнения, вероятно, слишком мало, чтобы требовать много потоков...