Zdravím, právě jsem napsal tento program, který by měl v jednom vláknu uložit zprávu do sdíleného listu a předat řízení druhému vláknu, které jej zobrazí. Problém ale je, že se to stane pouze jednou a pak se to zasekne v nekonečné smyčce .. nepodařilo se mi zjistit, kde konkrétně (zkoušel jsem to umístěním různých výpisů do míst, kde by se to mohlo seknout, ale pak už nedoběhl ani ten první cyklus .) Podle mě, bude problém ve špatné synchronizaci, ale nevím to konkrétněji. Děkuji za pomoc.
public class PostovniSchranka {
private static List <String> schranka = new ArrayList<String>();
private static boolean zobrazeno = true;
private static int p;
static class Vyvolavac implements Runnable {
public synchronized void run (){
while(true){
while (zobrazeno){
try {wait();} catch (InterruptedException e ){}
}
System.out.println(schranka.get(p));
p++;
zobrazeno = true;
notifyAll();
}
}
}
public static void main (String[]args){
Thread Odesli = new Thread (new Odesilatel());
Thread Vyvolej = new Thread (new Vyvolavac());
Vyvolej.setDaemon(true);
Odesli.start();
Vyvolej.start();
}
}
Tak jsem to vyřešil :D :D :D Neuvědomil jsem si, že každá ta třída (Odesilatel a Vyvolavac) má jiný zámek, takže k sobě nemají přístup :D
public class PostovniSchranka {
private static List <String> schranka = new ArrayList<String>();
private static boolean zobrazeno = true;
private static int p;
public static Object lock = new Object();
for ( p = 0; p< zpravy.length;p++){
synchronized (lock){
while (!zobrazeno){
try {lock.wait();} catch (InterruptedException e){}
}
schranka.add(zpravy[p]);
zobrazeno = false;
lock.notifyAll();
}
}
}
}
static class Vyvolavac implements Runnable {
public void run (){
while(true){
synchronized (lock){
while (zobrazeno){
try {lock.wait();} catch (InterruptedException e ){}
}
System.out.println(schranka.get(p-1));
zobrazeno = true;
lock.notifyAll(); }
}
}
}
public static void main (String[]args){
Thread Odesli = new Thread (new Odesilatel());
Thread Vyvolej = new Thread (new Vyvolavac());
Vyvolej.setDaemon(true);
Odesli.start();
Vyvolej.start();
}
}
Jen pro doplnění mých znalostí o principu fungování zámku ... proč v prvním případě proběhla první smyčka ? Je to tak, že ve skutečnosti neproběhla, jen když se první vlákno vzdalo svého zámku, tak se uvolnilo místo pro proběhnutí druhého cyklu s jiným zámkem, ale metoda notifyAll() vyšla vniveč ?
#3GoliathL
Odesilatel prostě po startu stihl odeslat první zprávu (a před druhou zůstal viset ve wait) a až pak se spustil Vyvolavac, který ji vyzvedl (a potom taky zůstal viset ve wait). Nebylo to zámkama, jen pořadím a trochu náhodou.
K tomu, co napsal "q" .... Myslím si správně, že metoda Wait() a notifyAll() (pripadne notify()) je vždy vázaná k vlastnímu zámku a ovlivňuje jen vlákna se stejným zámkem ? Tedy, že problém v prvním případě byl v tom, že druhé vlákno (Vyvolavac) proběhlo jen proto, že následovalo v pořadí za vláknem Odesilatel, ne proto, že by bylo informováno metodou notifyAll(). Je to důležité, protože v opačném případě to pak chápu tak, že nezáleží na zámku, který Wait() a NotifyAll() vyvolává, a tak ani nevím, proč to při udělení stejného zámku oboum vláknům (ten druhý, fungující případ) fungovalo.
Na tom objektu, na kterém zavoláš notify, na tom se "probudí" wait (pokud v něm někdo čeká).
Takže v té nefunkční variantě ti obě vlákna notifikují samy sebe a nic to neudělá, protože na to nikdo jiný nečeká a pak zase zůstanou viset ve waitu, protože je nikdo jiný neprobudí:
Aha, nerad dál zdržuju, ale při volání metody Wait() se tedy uvolní zámek a dokud není volána metoda notify() pro ten stejný zámek, tak Wait() stále trvá. Podmínkami while (nějaký boolean) pak zajišťuju to, aby si při volání metody notify() nevzalo zámek vlákno, které má ještě čekat. Tedy, při volání notify() nezáleží na tom, ve kterém je vlákně, ale kterým zámkem je volána.
Ještě důležitá věc je, že notify probudí čekající vlákno(vlákna), ale nic nedělá se zámkem. Takže to čekající vlákno se dozví o notify, ale z waitu vyleze až když převezme zámek. Tj. až ho to předchozí vlákno odemkne (opuštěním synchronized metody/bloku). To máš v té první variantě taky špatně.