Java Thread Wait-Notify - PullRequest
       4

Java Thread Wait-Notify

2 голосов
/ 20 октября 2010

У меня есть 3 потока (A, B, C), которые я просто не могу заставить их работать так, как я хочу.ВСЕ эти 3 потока разделяют ссылку на один и тот же объект - К. Что я пытаюсь сделать, это запустить все 3 вверх, а затем в какой-то момент времени, когда поток А приходит в определенное состояние, приостанавливать потоки В и С,пока A не выполнит какой-либо метод work () и когда работа завершится, возобновите B и C.

Теперь, что у меня есть в моем коде: поток A ссылается на B и C. B и C имеют метод pause () {synchronized (K) {k.wait;}} Когда A приходит в это определенное состояние, я вызываю из А метод run (): B.pause (), C.pause ().Теперь я ожидаю, что потоки B и C будут ждать до тех пор, пока кто-то не сделает: k.notifyAll (), НО вместо этого поток A останавливается.Это нормально в Java?

Код:

class A implements Runnable {
   private K k;
   private B b;
   private C c;

   void run() {
      while(something) {
         //do something
         b.pause();
         c.pause();
          // !!! here this thread will freeze and doSomething2 wont get executed.
          // what i want is to pause B, C, doSomething2 to get executed and then resume B and C
         //do something2 
         synchronized(k) {
           k.notifyAll();
         }
      }
   }
}
class B implements Runnable {
   private K k;


   void run() {
      while(something) {
         //dome something
         }
      }
   }
   public pause() {
       synchronized(k) { k.wait();}
   }
}
class C implements Runnable {
   private K k;


   void run() {
      while(something) {
         //dome something
         }
      }
   }
   public pause() {
       synchronized(k) { k.wait();}
   }
}

Ответы [ 7 ]

3 голосов
/ 20 октября 2010

Вы можете использовать CylcicBarrier для реализации этого.

CyclicBarrier barrier = new CyclicBarrier();

public void run() {
    new Thread(new A(barrier)).start();
    new Thread(new B(barrier)).start();

    barrier.await();  // Waits until all threads have called await()

    // Do something
}

public void A implements Runnable {
    private CyclicBarrier barrier;

    public A(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public void run() {
        barrier.await();
        // Do something.
    }
}

public void B implements Runnable {
    private CyclicBarrier barrier;

    public B(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public void run() {
        barrier.await();
        // Do something.
    }
}
1 голос
/ 20 октября 2010

Когда вы вызываете B.pause (), он выполняется в локальном потоке, а не в потоке, в котором вы вызвали метод run из B. Для этого в классе Thread есть некоторые устаревшие методы, но они опасны, см.здесь: http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

0 голосов
/ 21 октября 2010

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

class A implements Runnable {
   private K k;
   private B b;
   private C c;

   void run() {
      while(something) {
         //do something
         b.pause();
         c.pause();
          // !!! here this thread will freeze and doSomething2 wont get executed.
          // what i want is to pause B, C, doSomething2 to get executed and then resume B and C
         //do something2 
         synchronized(k) {
           k.notifyAll();
         }
      }
   }
}
class B implements Runnable {
   private K k;
   volatile boolean isPaused = false;


   void run() {
      while(something) {
         if (isPaused) {
           synchronized(k) { k.wait();}
           isPaused = false;
         }
         //dome something
      }
   }
   public pause() {
     isPaused = true;
   }
}
class C implements Runnable {
   private K k;
   volatile boolean isPaused = false;


   void run() {
      while(something) {
        if (isPaused) {
          synchronized(k) {
            k.wait();
          }
          isPaused = false;
        }
        //dome something
      }
   }
   public pause() {
     isPaused = true;
   }
}

Я предполагаю, что то, что вы действительно хотите сделать, это безусловное ожидание вызова на k в B и C, а затем всегда вызывать notifyAll в A

0 голосов
/ 20 октября 2010

Если я не понимаю ваше домашнее задание, я думаю, вам нужно научиться прерывать цепочку.B и C являются прерывистыми потоками, которые должны обрабатывать прерывания таким образом, чтобы они не возобновили работу, пока им не сказали, что все в порядке.Это может выглядеть примерно так:

while(true)
{
   try
   {
      Thread.sleep(100);
      System.out.println("Thread is working normally...");
   }
   catch(InterruptedException e)
   {
      System.out.println("Thread has been interrupted, will wait till A is done...");
      try
      {
         synchronized(monitor)
         {
           monitor.wait();
         }
      }
      catch(InterruptedException e2)
      {
         // whatever...
      }
   }
}

Так что объект A, работающий в своем собственном потоке, будет иметь ссылки на два других потока.Объект A будет иметь доступ к общему объекту монитора, к которому также имеют доступ runnables в двух других потоках (я назвал его monitor).Когда A прерывает другие потоки, их исполняемые программы будут вызывать wait() на мониторе.Когда A будет сделано, он вызовет notifyAll() на мониторе.ПРИМЕЧАНИЕ: вы должны сбросить флаг прерывания и в других потоках, но я оставлю это вам, чтобы разобраться - это легко:)

0 голосов
/ 20 октября 2010

Удалите вызовы b.pause() и c.pause() из A.run() и вызовите их из собственных методов выполнения.

0 голосов
/ 20 октября 2010

Вы знаете, что вы используете 3 разных объекта (мониторов) Ak, Bk, Ck?

Так что, когда B "сделал паузу", он синхронизируется на собственном мониторе (Bk), который должен быть свободен в любом случае.Ваши темы никак не "общаются".

0 голосов
/ 20 октября 2010

Вы уверены, что вызываете b.pause (), но объявляете B.sleep ()?

Было бы неплохо увидеть конструкцию потоков / стартовый код.

...