Zdravím,
potřebuji si ujasnit pravidla fungování metody notify() ...
public class prerusenipodminkou {
private final String jmeno;
private final int vek;
private final int vyska;
public static Object lock = new Object();
// public static Object lock2 = new Object();
private static boolean dokonceno = false;
private static String winner;
public prerusenipodminkou (String jmeno, int vek, int vyska){
this.jmeno = jmeno;
this.vek = vek;
this.vyska = vyska;
}
public synchronized int beh(){
return (this.vyska/2);
}
public void oznam (){
synchronized (lock){
dokonceno = true;
winner = this.jmeno;
lock.notifyAll();
}
}
public static void vitez(){
synchronized (lock){
while (!dokonceno){
try{ lock.wait();} catch (InterruptedException e){System.out.println("Z neznámého důvodu ani jeden z účastníků závod nedokončil");}
}
System.out.println( "vítězí " +winner);
}
}
static class zavod implements Runnable {
prerusenipodminkou zavodnik;
int delkadrahy;
public zavod (prerusenipodminkou zavodnik, int delkadrahy){
this.zavodnik = zavodnik;
this.delkadrahy = delkadrahy*100;
}
public void run(){
long pocatek = System.currentTimeMillis();
int vzdalenostcile = this.delkadrahy;
while (vzdalenostcile>0){
vzdalenostcile -= zavodnik.beh();
System.out.println(this.zavodnik.jmeno + " v čase "+(System.currentTimeMillis()-pocatek)/1000+" sekund uběhl "+(this.delkadrahy - vzdalenostcile) + " centimetrů");
try{Thread.sleep(this.zavodnik.vek*10);}catch (InterruptedException e ){}
}
if (!dokonceno){
this.zavodnik.oznam();
}
}
}
public static void main (String [] args){
prerusenipodminkou zavodnik = new prerusenipodminkou("Wozniak", 64, 180);
prerusenipodminkou zavodnik2 = new prerusenipodminkou("Newell", 52, 180);
Thread T = new Thread (new zavod(zavodnik, 10));
Thread k = new Thread (new zavod(zavodnik2,10));
Thread W = new Thread (new Runnable (){public void run(){vitez();}});
W.start();
T.start();
k.start();
}
}
Tento kód funguje, ale před tím jej bylo třeba upravit ... původní verze vypadala takto:
public class prerusenipodminkou2 {
private String jmeno;
private int vek;
private int vyska;
public static Object lock = new Object();
public static boolean dokonceno = false;
public static String winner;
public prerusenipodminkou2 (String jmeno, int vek, int vyska){
this.jmeno = jmeno;
this.vek = vek;
this.vyska = vyska;
}
public synchronized int beh(){
return (this.vyska/2);
}
public static void vitez(){
synchronized (lock){
while (!dokonceno){
try{ lock.wait();} catch (InterruptedException e){System.out.println("Z neznámého důvodu ani jeden z účastníků závod nedokončil");}
}
System.out.println( "vítězí " +winner);
}
}
static class zavod implements Runnable {
prerusenipodminkou2 zavodnik;
int delkadrahy;
public zavod (prerusenipodminkou2 zavodnik, int delkadrahy){
this.zavodnik = zavodnik;
this.delkadrahy = delkadrahy*100;
}
public synchronized void run(){
long pocatek = System.currentTimeMillis();
int vzdalenostcile = this.delkadrahy;
while (vzdalenostcile>0){
vzdalenostcile -= zavodnik.beh();
System.out.println(this.zavodnik.jmeno + " v čase "+(System.currentTimeMillis()-pocatek)/1000+" sekund uběhl "+(this.delkadrahy - vzdalenostcile) + " centimetrů");
try{Thread.sleep(this.zavodnik.vek*10);}catch (InterruptedException e ){}
}
if (!dokonceno){
winner = this.zavodnik.jmeno;
dokonceno = true;
lock.notifyAll();
}
}
}
public static void main (String [] args){
prerusenipodminkou2 zavodnik = new prerusenipodminkou2("Wozniak", 55, 185);
prerusenipodminkou2 zavodnik2 = new prerusenipodminkou2("Newell", 40, 150);
Thread T = new Thread (new zavod(zavodnik, 50));
Thread k = new Thread (new zavod(zavodnik2,50));
Thread W = new Thread (new Runnable (){public void run(){vitez();}});
W.start();
T.start();
k.start();
}
}
Problém byl v tom, že volání metody notifyAll pro zámek lock probíhalo ve vláknu, které bylo synchronizováno jiným zámkem. Dosud jsem si myslel, že nezáleží na zámku vlákna, ve kterém je notify() voláno (naopak při volání wait() ano), ale na zzámku, kterým notify() volám .... tedy, že mohu vlákno čekající na zámek A odemknout metodou A.notify() ať ji volám odkudkoliv. Co na tom je a není pravdy ?