Я пытаюсь переопределить мой параллельный код, используя CyclicBarrier
, который является новым для меня. Я могу обойтись без него, но я время возможности проверки его против моего другого решения, проблема у меня есть тупиковая ситуация со следующим кодом:Почему «ExecutorService» не может последовательно создавать потоки?
//instance variables (fully initialised elsewhere).
private final ExecutorService exec = Executors.newFixedThreadPool(4);
private ArrayList<IListener> listeners = new ArrayList<IListener>();
private int[] playerIds;
private class WorldUpdater {
final CyclicBarrier barrier1;
final CyclicBarrier barrier2;
volatile boolean anyChange;
List<Callable<Void>> calls = new ArrayList<Callable<Void>>();
class SyncedCallable implements Callable<Void> {
final IListener listener;
private SyncedCallable(IListener listener) {
this.listener = listener;
}
@Override
public Void call() throws Exception {
listener.startUpdate();
if (barrier1.await() == 0) {
anyChange = processCommons();
}
barrier2.await();
listener.endUpdate(anyChange);
return null;
}
}
public WorldUpdater(ArrayList<IListener> listeners, int[] playerIds) {
barrier2 = new CyclicBarrier(listeners.size());
barrier1 = new CyclicBarrier(listeners.size());
for (int i : playerIds)
calls.add(new SyncedCallable(listeners.get(i)));
}
void start(){
try {
exec.invokeAll(calls);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void someMethodCalledEveryFrame() {
//Calls some Fisher-something method that shuffles int[]
shufflePIDs();
WorldUpdater updater = new WorldUpdater(listeners, playerIds);
updater.start();
}
Я использую отладчик в Android Studio (IntelliJ), чтобы приостановить выполнение на этом сцена. Я получаю несколько потоков, показывающие мои await
звонки, как последний из моего кода, который будет выполнен
->
Unsafe.park
->
LockSupport.park
->
AbstractQueuedSynchronizer$ConditionObject.await
->
CyclicBarrier.doWait
->
CyclicBarrier.await
По крайней мере, один поток будет иметь этот стек:
->Unsafe.park
.
->LockSupport.park
->AbstractQueuedSynchronizer$ConditionObject.await
->LinkedBlockingQueue.take
->ThreadPoolExecutor.getTask
->ThreadPoolExecutor.runWorker
->ThreadPoolExecutor$Worker.run
->Thread.run
Я замечаю, что CyclicBarrier
не играет никакой роли в этих последних нисходящих потоках.
processCommons
является вызова exec.invokeAll
(на 3-х слушателей), я полагаю, это означает, что я бегу из нитей. Но много раз это не так, пожалуйста, может кто-нибудь уточнить, почему ExecutorService
не может постоянно планировать мои темы? У них есть свой стек и счетчик программ, поэтому я бы подумал, что это не проблема. Я только когда-либо бегу сразу. Кто-нибудь поможет мне в математике?
Я изначально одобрил это из-за вашего акцента на «_exactly_ four», «No more, not less», который оказался глубоким. Теперь я понимаю, что это просто неправильно: _like_ моя попытка использовать 'CyclicBarrier'. Он просто не подходит сюда, поэтому спасибо за этот указатель. – John