Синхронизация многих объектов и счетчика - PullRequest
0 голосов
/ 15 января 2012

Я знаю, что у многих людей есть проблемы с этой темой, и вам может быть скучно, но я пытаюсь понять это уже несколько дней и до сих пор не знаю, как это работает :(. У меня есть счетчик и другие объекты другого класса (в будущем более одного класса). Теперь каждый объект должен отвечать за выполнение счетчиков. Один счетчик - один шаг каждого метода запуска объекта. Это мой код:

public class Th {

  private final static Object lock1 = new Object();

////////////////////////////////////////////////////////////////////////////////

  private class Stop implements Runnable {

    private int count, id;

    public Stop(int id) {
      this.count = 0;
      this.id = id;
    }

    @Override public void run() {
      synchronized(lock1){
        while (count < 20) {
          try {
            lock1.wait();
          } 
          catch (InterruptedException exception) {
                System.out.println("Error!");
          }
          System.out.println(count + " stop " + id);
          this.count++;

//          try {
//            Thread.sleep(360);
//          }
//          catch (InterruptedException exception) {
//            System.out.println("Error!");
//          } 

        }
      }
    }

  } 

////////////////////////////////////////////////////////////////////////////////

  private class Counter implements Runnable {

    private int count;

    public Counter() {
      this.count = 0;
    }

    @Override public void run() {

      synchronized(lock1){
        while (count<15) {
          lock1.notifyAll();

          System.out.println(count + " counter");
          this.count++;      

//          try {
//            Thread.sleep(360);
//          }
//          catch (InterruptedException exception) {
//            System.out.println("Error!");
//          }          

        }
      }
    }

  } 

   public void test() {

     Stop s1 = new Stop(1);
     Stop s2 = new Stop(2);
     Stop s3 = new Stop(3);

     Counter counter = new Counter();

     (new Thread(s1)).start();
     (new Thread(s2)).start();
     (new Thread(counter)).start();
     (new Thread(s3)).start();


   }

}

и он возвращает мне что-то вроде:

run:
0 counter
1 counter
2 counter
3 counter
4 counter
5 counter
6 counter
7 counter
8 counter
9 counter
10 counter
11 counter
12 counter
13 counter
14 counter
0 stop 1

мне нужно:

0 counter
0 stop 0
0 stop 1
0 stop 2
1 counter
1 stop 0
1 stop 1
1 stop 2
2 counter
2 stop 0
2 stop 1
2 stop 2
3 counter
...

Ответы [ 2 ]

4 голосов
/ 15 января 2012

Весь цикл потока Counter синхронизирован с lock1. Это означает, что хотя вы и вызываете notifyAll в этом цикле, другие потоки не могут восстановить блокировку до тех пор, пока полный цикл не завершится в потоке Counter.

Сделайте каждую итерацию цикла синхронизированной, вместо синхронизации вне цикла.

Обратите внимание, что этого будет недостаточно, поскольку поток Counter может повторно захватить блокировку до того, как все потоки Stop ее повторно получат. Вам нужно будет заставить поток Counter ждать другое условие и перезапустить его, когда все потоки Stop отобразят счет.

Вы должны исследовать абстракции более высокого уровня, такие как CyclicBarrier и CountDownLatch.

3 голосов
/ 15 января 2012

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

Но если вы хотите сделать это "трудным путем" в качестве учебного упражнения, вам нужночтобы признать, что эта проблема требует, чтобы потоки Counter и Stop ожидали определенных «событий».

  • Потоки Stop должны ждать, пока поток Counter не скажет им перейти к следующей остановке.

  • Поток счетчика должен ждать, пока все Стоп-потоки не переместятся и не остановятся.

Одна проблема с вашим токомреализация состоит в том, что потоку Counter нечего сказать, когда все потоки Stop продвинулись и остановились.Вместо этого он предполагает, что, когда он видит событие уведомления, все в порядке, чтобы выполнить следующий счет.

...