Metody wait() a notify() - ujasnění – Java – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Metody wait() a notify() - ujasnění – Java – Fórum – Programujte.comMetody wait() a notify() - ujasnění – Java – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
GoliathL0
Newbie
31. 1. 2015   #1
-
0
-

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 ?

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

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.

Problém byl v tom, že jsi volal notify na zámku, který jsi pro sebe neměl zamčený.

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

 Dobře, takže to souvisí s tímto, co jsi mi nedávno odpověděl na obdobnou otázku: 


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

V tomto případě nebyl zámek lock ve chvíli, kdy na něm byla volána metoda notify() žádným vláknem vlastněn, a protože notify() jen oznamuje, že v nejbližší době může některé vlákno uvolnit tento zámek, načež je ještě třeba, aby byl daný zámek uvolněn, nic se nestalo ... lock.wait() bylo informováno o možném uvolnění zámku, ale zámek nebyl uvolněn, protože ani nebyl používán.

Nahlásit jako SPAM
IP: 89.102.251.–
Řešení
q
~ Anonymní uživatel
219 příspěvků
1. 2. 2015   #4
-
0
-
Vyřešeno Nejlepší odpověď

Ale ne, wait i notify na zámku může volat jen vlákno, které ho v tu chvíli vlastní (má ho zamčený).

Notify vůbec neproběhlo a nejspíš vyhodilo vyjímku.

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

Dobře, díky

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

Wait — založil Rišo Kakaš

Ujasnění pár věcí — založil Mutagen

Zápis objektu - ujasnění — založil GoliathL

Metody — založil Erik

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ý