2010-06-29 12 views
5
public class Main2 { 
    public static void main(String[] args) { 
     new Test2().start(); 
     new Test2().start(); 
    } 
} 

class Test2 extends Thread { 
    @Override 
    synchronized public void run() { 
     try { 
      System.out.println("begin wait"); 
      wait(); 
     } catch (Exception ex) { 
     } 
    } 
} 

Come il risultato effettivo di esecuzione del test: iniziano attesa, cominciano attesa, due volte dai due fili. Contrasto al risultato previsto: begin wait, solo una volta da uno dei due thread, perché wait() viene chiamato all'interno del metodo run() sincronizzato. Perché è possibile chiamare la sospensione del thread di attesa di Object()?Chiama per Java Object wait() rompe la sincronizzazione dei thread

Grazie mille!


public class Main3 { 

    public static void main(String[] args) { 
     Test3 t = new Test3(); 
     new Thread(t).start(); 
     new Thread(t).start(); 
    } 
} 

class Test3 implements Runnable { 
    synchronized public void run() { 
     try { 
      System.out.println("begin wait"); 
      wait(); 
     } catch (Exception ex) { 
     } 
    } 
} 

@akf & @Sean Owen

Grazie per le vostre risposte. Scusa per il mio errore, ora ho modificato il codice per posizionare la sincronizzazione sullo stesso oggetto run(), il risultato è rimasto: inizio attesa, inizio attesa, due volte.

@akf

attesa sarà rilasciare il blocco che sincronizzare ha afferrato, e sarà ri-ottenuto una volta che il filo viene notificato.

Potresti elaborare un po '?

risposta

2

Si dispone di due oggetti Test2 diversi. I metodi sincronizzati bloccano l'oggetto. Non stanno acquistando lo stesso lucchetto, quindi non dovrebbe stampare due volte.

10
  1. L'oggetto che si sincronizza in questo esempio non è la classe, ma l'istanza, così ogni nuovo oggetto Test2 sarebbe Sincronizzazione su un monitor diverso.
  2. Il metodo che si sta cercando qui è sleep, non wait. wait rilascia il blocco che ha acquisito il codice synchronized e verrà recuperato una volta notificato il thread.

Si noti che per il corretto funzionamento del test, è necessario bloccare un oggetto comune. Se vuoi vedere wait in azione, ho messo insieme una semplice app che farà apparire un frame con un pulsante "Notifica". Saranno avviati due thread che attendono su un oggetto comune e vengono a loro volta notificati quando viene premuto il pulsante.

public static void main(String[] args) 
{ 
    final Object lock = new Object(); 

    final JFrame frame = new JFrame("Notify Test"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    JButton button = new JButton("Notify"); 
    button.addActionListener(new ActionListener(){ 
     public void actionPerformed(ActionEvent evt) { 
      synchronized(lock) { 
       lock.notify(); 
      } 
     } 
    }); 
    frame.add(button); 

    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      frame.setVisible(true); 
     } 
    }); 

    new Thread(new Runnable() { 
     public void run() { 
      synchronized(lock) { 
       try { 
        System.out.println("1. starting"); 
        lock.wait(); 
        System.out.println("1. step 1"); 
        lock.wait(); 
        System.out.println("1. step 2"); 
       } catch (InterruptedException ie) { 
        ie.printStackTrace(); 
       } 
      } 
     } 
    }).start(); 
    new Thread(new Runnable() { 
     public void run() { 
      synchronized(lock) { 
       try { 
        System.out.println("2. starting"); 
        lock.wait(); 
        System.out.println("2. step 1"); 
        lock.wait(); 
        System.out.println("2. step 2"); 
       } catch (InterruptedException ie) { 
        ie.printStackTrace(); 
       } 
      } 
     } 
    }).start(); 

} 

Per una semplice spiegazione di wait, JavaDoc è sempre un buon punto di partenza:

causa il thread corrente di aspettare fino a quando un altro thread invoca il metodo notify() o il notifyAll() metodo per questo oggetto. In altre parole, questo metodo si comporta esattamente come se eseguisse semplicemente l'attesa di chiamata (0).

Il thread corrente deve possedere il monitor di questo oggetto. Il thread rilascia la proprietà di questo monitor e attende fino a quando un altro thread notifica i thread in attesa sul monitor di questo oggetto per attivarsi tramite una chiamata al metodo notify o al metodo notifyAll. Il thread quindi attende fino a quando non è possibile ottenere nuovamente la proprietà del monitor e riprende l'esecuzione.

+0

Grazie per l'esempio e riferimento javadoc! – sof

+1

Potrebbe essere utile notare che la scelta del thread da riattivare è arbitraria. Una buona implementazione sarà equa e notificherà i thread nell'ordine in cui hanno chiamato wait(), ma non è obbligatorio. Quindi l'unico vincolo è che '[N]. il passaggio 1' prima di '[N]. passo 2', dove N è consistentemente 1 o 2. –

+0

@ Mark Peters, questo è un buon punto per fare - anche se potrebbe non sembrare arbitrario (cioè, la prova empirica potrebbe cercare di convincerti che è ordinata), lì non è una garanzia. – akf

1

un semplice esempio che può aiutare è questo:

 public class test { 
      public static void main(String[] args) { 
       Prova a=new Prova(); 
       new Test2(a).start(); 
       new Test2(a).start(); 
      } 
     } 
     class Prova{ 
      private boolean condition; 

      public void f(){ 

       while(condition){ 
        //Thread.currentThread Returns a reference to the currently executing thread object. 
        //Thread.getName() return name Thread 
        System.out.println(Thread.currentThread().getName()+" begin wait"); 
        try{ 
         wait(); 
        }catch(InterruptedException c){return;} 
       }  

       System.out.println(Thread.currentThread().getName()+" first to take the mutex"); 
       condition=true; 

      } 
     } 
     class Test2 extends Thread { 
      private Prova a; 
      private static boolean condition; 


      public Test2(Prova a){ 
       this.a=a; 
      } 
      @Override 

      public void run() { 
       synchronized(a){ 
       try {   
        a.f();   
       } catch (Exception ex) { 
       } 
       } 
      } 
     } 

in questo caso i due fili sincronizzano un oggetto, la prima prendendo il messaggio di sblocco, il secondo si attende. In questo esempio si utilizza la variabile condizione

-1

sintesi aspettare/notifica meccanismo:

1) thread corrente raggiunge blocco di codice sincronizzato un oggetto che contiene la chiamata di attesa(), compete con altri fili per la lock (il monitor dell'oggetto), come vincitore esegue il blocco fino agli incontri call to wait().

2) chiamando wait(), il thread corrente rilascia il blocco ad altri thread concorrenti, quindi interrompe l'esecuzione, attende che venga inviata una notifica da un altro thread che riesce ad ottenere il blocco.

JavaDoc:

Un filo diventa il proprietario monitor dell'oggetto in uno dei tre modi :

• Eseguendo un metodo di quell'oggetto esempio sincronizzato.

• Eseguendo il corpo di una istruzione sincronizzata che si sincronizza sull'oggetto.

• Per oggetti di tipo classe, eseguendo un metodo statico sincronizzato di detto classe.

3) altro thread raggiunge ancora un altro blocco di codice sincronizzato dello stesso oggetto che contiene la chiamata di notifica/notifyAll(), compete con altri fili per la serratura, vincitore si esegue il blocco fino finendo la chiama per notificare/notifyAll(). Rilascerà il blocco sia da call to wait() che alla fine dell'esecuzione sul blocco.

4) dopo aver ricevuto notifica/notifyAll(), il thread corrente compete per il blocco, poiché come vincitore l'esecuzione continua dove è stata interrotta.

semplice esempio:

public class Main3 { 

    public static void main(String[] args) { 
     Test3 t = new Test3(); 
     new Thread(t).start(); 
     new Thread(t).start(); 
     try { 
      Thread.sleep(1000); 
     } catch (Exception ex) { 
     } 
     t.testNotifyAll(); 
    } 
} 

class Test3 implements Runnable { 

    synchronized public void run() { 

     System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock"); 
     try { 
      wait(); 
     } catch (Exception ex) { 
     } 
     System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock again"); 
     try { 
      Thread.sleep(1000); 
     } catch (Exception ex) { 
     } 
     System.out.println(Thread.currentThread().getName() + ": " + "bye wait block"); 

    } 

    synchronized void testNotifyAll() { 
     System.out.println(Thread.currentThread().getName() + ": " + "notify block got the lock"); 
     notifyAll(); 
     System.out.println(Thread.currentThread().getName() + ": " + "notify sent"); 
     try { 
      Thread.sleep(2000); 
     } catch (Exception ex) { 
     } 
     System.out.println(Thread.currentThread().getName() + ": " + "bye notify block"); 
    } 
} 

uscita:

Thread-0 (o 1): attendere blocco ottenuto il bloccare

Thread-1 (o 0): attendere blocco ottenuto il blocco

principale: blocco notifica ottenuto il blocco

principale: notify inviato

principale: bye notificare blocco

Thread-0 (o 1): wait blocco ottenuto il blocco di nuovo

Thread-0 (o 1): bye attendere bloccare

thread-1 (o 0): wait blocco ottenuto il blocco di nuovo

thread-1 (o 0): da e wait block

Problemi correlati