Как мне заставить java.concurrency.CyclicBarrier работать как положено - PullRequest
7 голосов
/ 26 марта 2010

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

 class mythread extends Thread{
   CyclicBarrier barrier;
   public mythread(CyclicBarrier barrier) { 
       this.barrier = barrier;
      }

   public void run(){
            barrier.await();
       } 
 }



class MainClass{
 public void spawnAndWait(){
    CyclicBarrier barrier = new CyclicBarrier(2);
    mythread thread1 = new mythread(barrier).start();
    mythread thread2 = new mythread(barrier).start();
    System.out.println("Should wait till both threads finish executing before printing this");
  }
}

Есть идеи, что я делаю не так? Или есть лучший способ написать эти методы синхронизации барьера? Пожалуйста помоги.

Ответы [ 4 ]

14 голосов
/ 26 марта 2010

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

CyclicBarrier barrier = new CyclicBarrier(3);
mythread thread1 = new mythread(barrier).start();
mythread thread2 = new mythread(barrier).start();
barrier.await(); // now you wait for two new threads to reach the barrier.
System.out.println("Should wait till both threads finish executing before printing this");

КСТАТИ. Не расширяйте класс Thread, если это не нужно. Реализуйте Runnable и передайте реализации объектам Thread. Как это:

class MyRunnable implements Runnable {
    public void run(){
        // code to be done in thread
    }
}

Thread thread1 = new Thread(MyRunnable);
thread1.start();

EDIT
Обоснование избегания расширения темы.
Эмпирическое правило - это как можно меньше связи. Наследование - это очень сильная связь между классами. Вы должны наследовать от Thread, если хотите изменить некоторые из его поведений по умолчанию (т.е. переопределить некоторые методы) или хотите получить доступ к некоторым защищенным полям класса Thread. Если вы не хотите этого, вы выбираете более слабую связь - реализует Runnable и передает его в качестве параметра конструктора в экземпляр Thread.

2 голосов
/ 26 марта 2010

Вы ищете Thread.join () метод ...

thread1.join();
thread2.join();
System.out.println("Finished");

РЕДАКТИРОВАТЬ: из-за комментариев ...

И если вы не хотите ждать вечно, вы также можете указать максимальное количество миллисекунд плюс наносекунды, в течение которых поток умирает

2 голосов
/ 26 марта 2010

Передайте экземпляр Runnable в конструктор вашего CyclicBarrier следующим образом.

CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() {

    @Override
    public void run() {
        System.out.println("Should wait till both threads finish executing before printing this");
    }
});

new mythread(barrier).start();
new mythread(barrier).start();
1 голос
/ 20 сентября 2011

Циклический барьер не является правильным выбором в этом случае. Вы должны использовать CountDownLatch здесь.

Я предполагаю, что вы вызываете метод spawnAndWait из основного метода.

Причина, по которой это не сработает, состоит в том, что CyclicBarrier имеет 2 конструктора. Для выполнения постопераций вы должны использовать двухпараметрический конструктор. Самая важная вещь, которую нужно помнить, это то, что основной поток не будет ждать методом await; но продолжу выполнять. Однако поток, указанный в конструкторе CyclicBarrier, будет работать только тогда, когда все порожденные потоки останавливаются на барьере (методом await)

...