CyclicBarrier не работает должным образом
Я пытаюсь смоделировать соревнования по триатлону, используя CyclicBarrier
но это не работает, как ожидалось, и я не знаю почему.
Каждая часть соревнования должна ждать, пока все бегуны не закончили предыдущий, но кажется, что он ждет вечно.
Это кусок кода для первого этапа:
class Runner implements Runnable
{
private CyclicBarrier bar = null;
private static int runners;
private static double[] time;
private int number;
public static String name;
public Runner(int runners, String name)
{
time = new double[runners];
for (int i=0; i<runners; i++)
time[i] = 0;
this.name= name;
}
public Runner(CyclicBarrier bar, int number)
{
this.bar = bar;
this.number = number;
}
public void run()
{
try { int i = bar.await(); }
catch(InterruptedException e) {}
catch (BrokenBarrierException e) {}
double tIni = System.nanoTime();
try { Thread.sleep((int)(100*Math.random()); } catch(InterruptedException e) {}
double t = System.nanoTime() - tIni;
time[number] += t;
}
}
public class Triatlon
{
public static void main(String[] args)
{
int runners = 100;
CyclicBarrier Finish_Line_1 = new CyclicBarrier (runners);
Runner c = new Runner(runners, "Triatlon");
ExecutorService e = Executors.newFixedThreadPool(runners);
for (int i=0; i<runners; i++)
e.submit(new Runner(Finish_Line_1, i));
System.out.println(Finish_Line_1.getNumberWaiting()); // this always shows 99
try { int i = Finish_Line_1.await(); }
catch(InterruptedException e01) {}
catch (BrokenBarrierException e02) {}
System.out.println("Swimming phase completed");
// here the rest of the competition, which works the same way
}
}
2 ответа
CyclicBarrier
циклы вокруг, как только все стороны вызвали, ждут, и барьер открыт. Отсюда и название. Так что, если вы создаете это с 5 сторон, и есть 6 звонков await
последняя заставит его ждать еще 4 партии, чтобы присоединиться.
Это в основном то, что здесь происходит, так как у вас есть 1 дополнительный await
позвони в свою главную. Он ждет очередных звонков "Бегуны-1".
Простое решение заключается в создании CyclicBarrier
с бегунами +1 партия.
У вас есть ошибка: вы создаете CyclicBarrier
для 100 потоков, но выполнить 101 await
s, одноразовый в основном методе. Из-за семантики циклического барьера и с учетом недетерминированных условий ваш основной поток будет выполняться последним await
тем самым оставаясь в одиночестве в ожидании присоединения еще 99 потоков.
После исправления этой проблемы вы обнаружите, что приложение продолжает работать даже после того, как вся работа выполнена. Это потому что ты не звонил e.shutdown()
, так что все потоки в пуле остаются живыми после того, как основной поток сделан.
КСТАТИ getNumberWaiting
всегда показывает 0 для меня, что является ожидаемым значением после того, как барьер был снижен из-за того, что 100 поданных потоков достигли его. Однако это недетерминировано и может измениться в любое время.