Java повторно использовать исполнителя - PullRequest
5 голосов
/ 27 января 2012

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

ExecutorService executor = Executors.newFixedThreadPool(nThread);
for (Model m : models) {
  executor.execute( m.simulationTask() );
}
executor.shutdown();
while ( ! executor.awaitTermination(10, TimeUnit.MINUTES) ) { 
  System.out.println("wait"); 
}

Теперь исполнитель не может быть использован для execute() новых задач после вызова shutdown().Есть ли способ перезагрузить исполнителя, чтобы я мог повторно использовать существующего исполнителя (и его потоки) на следующем этапе моделирования?

Ответы [ 4 ]

7 голосов
/ 27 января 2012

Вы можете повторно использовать службу executor, если вы несколько реструктурируете свой код.

Collection<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>(16);
for (Model m : models) {
  tasks.add(m.simulationTask());
}

ExecutorService executor = Executors.newFixedThreadPool(nThread);
try {
  executor.invokeAll(tasks);
} catch(InterruptedException ie) {
  // Handle this
}

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

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

1 голос
/ 27 января 2012

Объявите ваш ExecutorService как член вашего класса и используйте его по своему усмотрению. Не вызывайте shutDown () для него, так как он не будет принимать больше задач. Конечно, ваши задачи должны хорошо заканчиваться, и они также должны завершаться в какой-то момент.

1 голос
/ 27 января 2012

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

Учитывая, что shutdown()скорее всего, будет много очистки и сборки мусора, не совсем понятно, почему перезапуск будет лучше, чем получение нового Executor, возможно, вам следует изучить уроки о расширении ThreadPoolExecutor с помощью набора паузы / возобновленияметоды вместо добавления возможности отключения.

0 голосов
/ 27 января 2012

Просто приобретите еще ExecutorService.Затраты в любом случае минимальны.

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

// globally visible objects
AtomicInteger counter = new AtomicInteger(0);
Object signal = new Object();

ExecutorService executor = Executors.newFixedThreadPool(nThread);
for (Model m : models) {
  counter.getAndIncrement();
  executor.execute( m.simulationTask() );
}

synchronized(signal) {
   while(count.get() > 0) {
       signal.wait();
   }
}

Тогда внутри run ваших задач:

public void run() {
    // original code
    // at the end:
    synchronized(signal) {
       counter.getAndDecrement();
       signal.notify();
    }        
}
...