Как синхронизировать 4 потока?
Товарищи помогите! Написал программу реализующую 4 потока каждый из которых поочередно выводит на консоль сообщение из enum. НО не могу синхронизировать потоки, т.е. после выполнения последнего - первый не выходит из режима ожидания. Хотя я меняю флаговую переменную на соответствующее значение и разблокирую поток методом notify().
enum Score {
ONE, TWO, THREE, FOUR
}
class RealScore {
private static String state = "four";
public synchronized void One () {
try {
while (!state.equals("four")) wait();
} catch (Exception exe) {}
System.out.print (Score.ONE+" ");
state = "one";
notify();
return;
}
public synchronized void Two () {
try{
Thread.sleep(333);
while (!state.equals("one")) wait();
} catch (Exception exe) {}
System.out.print (Score.TWO+" ");
state = "two";
notify();
return;
}
public synchronized void Three () {
try {
Thread.sleep(666);
while (!state.equals("two")) wait();
} catch (Exception exe) {}
System.out.print (Score.THREE+" ");
state = "three";
notify();
return;
}
public synchronized void Four () {
try {
Thread.sleep(999);
while (!state.equals("three")) wait();
} catch (Exception exe) {}
System.out.println (Score.FOUR);
state = "four";
notify();
return;
}
}
class Potok extends Thread {
RealScore rs;
Potok (String name) {
super (name);
rs = new RealScore();
}
public static Potok crStart (String name) {
Potok ob = new Potok (name);
ob.start();
return ob;
}
public void run() {
try {
if (getName().equals("One")) {
for (int i=0; i<20; i++) {
rs.One();
}}
if (getName().equals("Two")) {
for (int i=0; i<20; i++) {
rs.Two();
}}
if (getName().equals("Three")) {
for (int i=0; i<20; i++) {
rs.Three();
}}
if (getName().equals("Four")) {
for (int i=0; i<20; i++) {
rs.Four();
}}
} catch (Exception exe) {
System.out.println ("Oshibka1: "+exe);}
}
}
class Prog268 {
public static void main (String args[]) {
System.out.println ("Score RUN!");
Potok ob1 = Potok.crStart("One");
Potok ob2 = Potok.crStart("Two");
Potok ob3 = Potok.crStart("Three");
Potok ob4 = Potok.crStart("Four");
try {
ob1.join();
ob2.join();
ob3.join();
ob4.join();
} catch (Exception exe) {
System.out.println ("Oshibka2: "+exe);}
System.out.println ("Score FINISH!");
}}
Ответы (1 шт):
Тут сразу несколько проблем:
Нужно использовать notifyAll вместо notify
Используйте notifyAll.
notify будит только один из ждущих потоков и далеко не факт, что он разбудит тот, который вам нужен. И когда такое происходит, то разбуженый поток, проверит условие и продолжит ждать. А новый notify уже никто не пошлет. И все - у вас потоки ждут на wait вечно.
Вы можете это проверить посмотрев стектрейсы в момент, когда програма застопорилась - они будут все ждать на wait.
wait-notifyAll должны использовать тот же объект
Сейчас все запускаемые потоки используют разные объекты и нотификации вообще не доходят
Игнорируются исключения
У вас в потоках, ловятся все исключения и просто игнорируются. Это прячет ошибки, и они просто не показываются.
Вот как можно исправить все:
class RealScore {
private static String state = "four";
Object sync;
public RealScore(Object sync) {
this.sync = sync;
}
public void One() {
synchronized (sync) {
try {
while (!state.equals("four"))
sync.wait();
} catch (InterruptedException exe) {
Thread.currentThread().interrupt();
System.out.println("Exception: " + exe);
}
System.out.print(Score.ONE + " ");
state = "one";
sync.notifyAll();
return;
}
}
... дальше аналогично
class Potok extends Thread {
RealScore rs;
Potok (String name, Object sync) {
super (name);
rs = new RealScore(sync);
}
public static Potok crStart (String name, Object sync) {
Potok ob = new Potok (name, sync);
ob.start();
return ob;
}
...
...
Object sync = new Object();
Potok ob1 = Potok.crStart("One", sync);
Potok ob2 = Potok.crStart("Two", sync);
Potok ob3 = Potok.crStart("Three", sync);
Potok ob4 = Potok.crStart("Four", sync);
....