2012-10-21 10 views
6

Mi chiedo se sia possibile in java avere una classe che implementa Runnable e se un oggetto della classe va in attesa() (quindi il thread smette di funzionare finché non riceve un segnale), un altro oggetto della stessa classe può notificarlo per continuare a funzionare?Come uso wait/notifyAll

Idealmente quello che voglio essere in grado di fare è:

public class ThreadClass implements Runnable{ 

public void run(){ 
//.. Does some arbitrary work 

    if(aCondition){ //have it wait until something signals it to contine exection. 
this.wait(); 
} 

//Continues to do more work. 

//finished whatever it needed to do. Signal all other threads of this object type to continue their work. 
this.notifyAll(); 

} 
} 

Questo è possibile e se sì, come dovrei andare a farlo? Sto cercando di farlo in modo che l'oggetto stesso possa gestire se stesso e tutti gli altri oggetti dello stesso tipo. In modo che nessuno che utilizza questa classe deve preoccuparsi di gestirlo.

risposta

6

Sto cercando di farlo in modo che l'oggetto stesso possa gestire se stesso e tutti gli altri oggetti dello stesso tipo. In modo che nessuno che utilizza questa classe deve preoccuparsi di gestirlo.

Se si desidera rendere ogni istanza a conoscenza di ogni altra istanza, è necessario un qualche tipo di raccolta statica ... che rende difficile la raccolta dei dati inutili, oltre a rendere tutto molto difficile da testare.

Suggerirei di avere un tipo di gestore separato il cui unico compito è gestire le istanze di questa classe. Allora hai solo bisogno di avere la logica in un posto, ma non hai bisogno di sapere su tutte le istanze del tipo - il gestore ha solo bisogno di sapere cosa sta gestendo. Potresti anche essere in grado di creare l'API in modo che il codice client solo debba visualizzare il gestore e che le singole istanze siano nascoste.

EDIT: Giusto per chiarire, non si può nemmeno bisogno wait/notifyAll a tutti - preferiscono i costrutti di livello superiore in java.util.concurrent, che permettono di scrivere scenari produttore/consumatore senza operazioni di basso livello, come wait. Questa risposta affronta la domanda di livello superiore di lasciare che gli oggetti sappiano con quali altri oggetti dovrebbero comunicare. L'idea della domanda di tutti gli oggetti di un tipo conoscendo un altro porterà a problemi, da qui il suggerimento di una classe manager.

+0

Qualsiasi aiuto su come rendere il manager? attualmente ho solo una classe che crea il mio oggetto thread, ma non tutti i thread saranno messi in pausa- mi aspetto che i thread da 1/10 debbano fermarsi finché una risorsa non viene rilasciata da un altro thread. – user597608

+0

@ user597608: avremmo bisogno di sapere più informazioni - non sappiamo davvero nulla di ciò che questo sta tentando di fare. Se puoi rendere responsabile il tuo manager per la creazione di ogni istanza, allora può passare un riferimento a se stesso a ciascuna delle istanze, in modo che possano richiamare quando devono segnalare qualcosa alle altre istanze gestite dallo stesso manager ... che ti aiuti? –

+0

Sto facendo un server che aspetta le chiamate UDP. Ottiene un messaggio e crea un nuovo thread che analizza il messaggio e quindi lo inserisce in un database SQLite. Sto riscontrando il problema che i blocchi di database sono dovuti al fatto che un database SQLite è un file. Ho provato un pool di connessioni (BoneCP), ma ha degradato le prestazioni del mio codice di un 1/10. Al momento il mio server è in grado di gestire 10 msg/secondo, ma uno superiore a quello e craps fuori. – user597608

1
If(condition) 
{ wait } 

Idealmente l'attesa dovrebbe essere racchiusa tra condizione mentre invece se blocco. Perché il cliente deve assicurarsi che la condizione sia soddisfatta prima di andare avanti invece di affidarsi esclusivamente alla notifica.

1

Gestendo se stesso, si potrebbe voler dire gestire la sincronizzazione sui blocchi e rispettare i limiti per le sue variabili di istanza in base ad alcune condizioni.

public class ThreadClass implements Runnable { 

    public void run() { 
     // .. Does some arbitrary work 
     synchronized (this) { 
      while (! aCondition) { // have it wait until something signals it to 
           // contine exection. 
       this.wait(); 
      } 
     } 

    /* Reset the aCondition var to its old value to allow other threads to 
     enter waiting state 

     Continues to do more work. 

     Finished whatever it needed to do. Signal all other threads of this 
     object type to continue their work.*/ 
     synchronized (this) { 
      this.notifyAll(); 
     } 

    } 
} 

Si consiglia inoltre di dare un'occhiata all'interfaccia Condition. Sembra avere gli stessi identici requisiti tranne che utilizza le classi java.util.concurrent. C'è un esempio di BoundedBuffer.

Vedere l'Esempio di consumatore produttore di seguito. Ha lo stesso modello di attesa/notifica. Il flag disponibile è volatile in modo che su di esso possano essere eseguite letture e scritture thread-safe.

public class ProducerConsumerTest { 
    public static void main(String[] args) { 
     CubbyHole c = new CubbyHole(); 
     Producer p1 = new Producer(c, 1); 
     Consumer c1 = new Consumer(c, 1); 

     p1.start(); 
     c1.start(); 
    } 
} 



    class CubbyHole { 
     private int contents; 
     private volatile boolean available = false; 

     public int get() { 
      synchronized (this) { 
       while (available == false) { 
        try { 
         wait(); 
        } catch (InterruptedException e) { 
        } 
       } 
      } 

      available = false; 
      synchronized (this) { 
       notifyAll(); 
      } 
      return contents; 
     } 

     public void put(int value) { 
      synchronized (this) { 
       while (available == true) { 
        try { 
         wait(); 
        } catch (InterruptedException e) { 
        } 
       } 
      } 
      available = true; 

      contents = value; 

      synchronized (this) { 
       notifyAll(); 
      } 
     } 
    } 

    class Consumer extends Thread { 
     private CubbyHole cubbyhole; 
     private int number; 
     private Integer takeSum = new Integer(0); 

     public Consumer(CubbyHole c, int number) { 
      cubbyhole = c; 
      this.number = number; 
     } 

     public Integer getTakeSum() { 
      return takeSum; 
     } 

     public void run() { 
      int value = 0; 
      for (int i = 0; i < 100; i++) { 
       value = cubbyhole.get(); 
       takeSum+=value; 

      } 

      System.out.println("Take Sum for Consumer: " + number + " is " 
        + takeSum); 
     } 
    } 

    class Producer extends Thread { 
     private CubbyHole cubbyhole; 
     private int number; 
     private Integer putSum = new Integer(0); 

     public Integer getPutSum() { 
      return putSum; 
     } 

     public Producer(CubbyHole c, int number) { 
      cubbyhole = c; 
      this.number = number; 
     } 

     public void run() { 
      for (int i = 0; i < 100; i++) { 
       int rnd = (int) (Math.random() * 10); 
       cubbyhole.put(rnd); 
       putSum+=rnd; 
       try { 
        sleep((int) (Math.random() * 100)); 
       } catch (InterruptedException e) { 
       } 
      } 
      System.out.println("Put Sum for Producer: " + number + " is " + putSum); 

     } 
    } 
+0

Ho provato questo e l'unico problema che ho riscontrato è che i thread – user597608

+0

L'esempio Producer-Consumer di CubbyHole è un buon modo per comprendere il meccanismo wait/notify, l'ho fatto nello stesso modello di cui sopra. – clinton

1

hai chiesto

può un altro oggetto della stessa classe notifica di continuare l'esecuzione?

Assolutamente si! - se gli oggetti sono bloccati in attesa su questo oggetto chiamando notifyAll da qualsiasi istanza di qualsiasi classe consentirà loro di eseguire. (incluso il Runnable in attesa su se stesso)

notifyAll non si preoccupa del tipo di classe che notifica, notifica QUALSIASI classe che è in attesa su questo oggetto. (usandolo come una serratura).

E per questo qualsiasi istanza di qualsiasi classe può chiamare attendere o notificare su qualsiasi oggetto. attendere e notificare sono metodi pubblici su java.lang.Object

Vedere questo tutorial in attesa, notifica.

http://www.java-samples.com/showtutorial.php?tutorialid=306

+0

L'OP non ha "posato" domanda errata "- ha pubblicato un codice che non fa ciò che vuole, ma non è la stessa cosa. –