Problém s vlákny – Java – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Problém s vlákny – Java – Fórum – Programujte.comProblém s vlákny – Java – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené.
GoliathL0
Newbie
27. 1. 2015   #1
-
0
-

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 Odesilatel implements Runnable {
    String [] zpravy =  {"1. cyklus", "2. cyklus", "3. cyklus", "4. cyklus", "poslední cyklus"};
    public synchronized void run(){
        
      for ( p = 0; p< zpravy.length;){  
    while (!zobrazeno){
     try {wait();} catch (InterruptedException e){}
     }
    
    schranka.add(zpravy[p]);
    zobrazeno = false; 
    notifyAll();

  }
}

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();
 }
 }

Nahlásit jako SPAM
IP: 89.102.251.–
GoliathL0
Newbie
27. 1. 2015   #2
-
0
-

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();

 static class Odesilatel implements Runnable {
    String [] zpravy =  {"1. cyklus", "2. cyklus", "3. cyklus", "4. cyklus", "poslední cyklus"};
    public void run(){
        
      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();
 }
 }

Nahlásit jako SPAM
IP: 89.102.251.–
GoliathL0
Newbie
27. 1. 2015   #3
-
0
-

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č ? 

Nahlásit jako SPAM
IP: 89.102.251.–
q
~ Anonymní uživatel
219 příspěvků
28. 1. 2015   #4
-
0
-

#3 GoliathL
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.

Nahlásit jako SPAM
IP: 213.211.51.–
sleepy
~ Anonymní uživatel
422 příspěvků
28. 1. 2015   #5
-
0
-

pouzivaj Lock a Condition na synchronizaciu, to sa potom riesi samo.

Nahlásit jako SPAM
IP: 158.195.201.–
GoliathL0
Newbie
28. 1. 2015   #6
-
0
-

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.

Nahlásit jako SPAM
IP: 89.102.251.–
q
~ Anonymní uživatel
219 příspěvků
28. 1. 2015   #7
-
+1
-
Zajímavé

#6 GoliathL

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í:

public synchronized void run() { // this.lock()
    ...
    wait();                      // this.wait() = this.unlock()
                                 //             + this.pockejNaNotify()
                                 //             + this.lock()
    ...
    notify();                    // this.notify();
}                                // this.unlock();

Ve druhé variantě obě vlákna pracují se stejným zámkem, takže ty notifikace jiného vlákna "vidí":

public void run () {
    ...
    synchronized (lock) {        // lock.lock();
        ...
        lock.wait();             // lock.wait() = lock.unlock()
                                 //             + lock.pockejnaNotify()
                                 //             + lock.lock()
        ...
        lock.notify();           // lock.notify();
    }                            // lock.unlock();
    ...
}
Nahlásit jako SPAM
IP: 213.211.51.–
GoliathL0
Newbie
28. 1. 2015   #8
-
0
-

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.

Nahlásit jako SPAM
IP: 89.102.251.–
q
~ Anonymní uživatel
219 příspěvků
28. 1. 2015   #9
-
+1
-
Zajímavé

Ano.

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ě.

Nahlásit jako SPAM
IP: 213.211.51.–
GoliathL0
Newbie
28. 1. 2015   #10
-
0
-

Dobře, to mi moc pomohlo. Děkuji.

Nahlásit jako SPAM
IP: 89.102.251.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 2 hosté

Podobná vlákna

Problém s vlákny — založil LordFaltus

Problem s vlakny — založil Lukas

Projekt s vlákny — založil Deyv

Peklo s vlákny — založil Sefiros

Prace s vlakny sleep/interrupt — založil rybar73

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý