În acest articol, ne vom uita la metoda wait() pentru a controla firul și la metodele notify() / notifyAll() . Aceste metode sunt definite în clasa de bază java.lang.Object și, în consecință, mecanismele de moștenire care sunt în Java oferă aceste metode pentru absolut toate clasele. Adică, atunci când vă creați propria clasă și obiectele acesteia, puteți apela oricând aceste metode.

Cum funcționează metodele wait() și notify()/notifyAll()?

  • așteptați() . pe scurt, această metodă eliberează monitorul și pune firul care apelează într-o stare de așteptare până când un alt fir apelează metoda notify() / notifyAll() ;
  • notifică () . Continuă munca unui fir a cărui metodă wait() a fost apelată anterior;
  • Metoda notifyAll() reia toate firele de execuție cărora li sa apelat anterior metoda wait() .
Acum să aruncăm o privire mai atentă la metoda wait() . Clasa Object conține trei opțiuni pentru această metodă:
  • public final nativ void wait(long timeoutMillis) aruncă InterruptedException ; Determină firul curent să aștepte până când este trezit. De obicei, se întâmplă prin a fi notificat sau întrerupt, sau până când a trecut o anumită perioadă de timp real.

  • public final void wait() aruncă InterruptedException . Nu întâmplător am scris o metodă fără parametri ca a doua. De fapt, dacă te uiți la codul său, se referă la prima variantă a metodei, are doar argumentul 0L.

  • așteptare finală publică (timeout lung, int nanos) . Determină firul curent să aștepte până când este trezit, de obicei prin notificare sau întrerupere, sau până când a trecut o anumită perioadă de timp real.

Metoda wait() are scopul de a suspenda firul de execuție apelant. Ce înseamnă? Aceste metode aparțin clasei. Pe baza clasei, creezi un obiect. În unele fire există obiecte. Adică, obiectele sunt create în unele fire. În firul în care funcționează acest obiect, dacă apelați wait() în el, acest lucru va duce la faptul că acest thread se va opri. Obiectul în sine acționează ca un fel de monitor. Ce este? Este clar că puteți crea diferite obiecte și toate vor conține wait()metodă. Există o înțelegere a ce obiect a cauzat oprirea unui anumit fir. Firul se oprește și va aștepta atâta timp cât este scris în parametru. Și apoi va începe. Acest thread nu poate începe singur. Pentru a relua munca, există metode notify și notifyAll. Un apel la notify() sau notifyAll() trebuie să joace un alt fir. Cu wait() , puteți opri mai multe fire și puteți începe toate firele cu notifyAll() . Dacă mai multe fire de execuție au fost oprite și a fost apelată notify() , este imposibil să spunem exact care fir de execuție va relua această metodă. Dacă nu există fire în așteptare pe metoda wait() , atunci nu se întâmplă nimic când notify() saunotifyAll() este apelat. Un fir de execuție poate apela metodele wait() sau notify() pe un anumit obiect numai dacă are în prezent o blocare pe acel obiect. wait() , notify() și notifyAll() ar trebui să fie apelate numai din codul sincronizat.

Exemplu de metodă Wait().

Aici avem unul dintre cele mai populare exemple care ilustrează modul în care funcționează metoda. Să presupunem că avem un magazin, un producător și un consumator. Producătorul transferă unele produse de producție în magazin, după care consumatorul le poate lua. Lăsați producătorul să producă 8 bunuri, respectiv, consumatorul trebuie să le cumpere pe toate. Dar, în același timp, în depozit nu pot fi mai mult de 6 articole în același timp. Pentru a rezolva această problemă, folosim metodele wait() și notify() . Să definim trei clase: piață , producător și client . Metoda Manufacturer in the run() adaugă 8 produse la obiectul Market utilizând- ometoda put() . Clientul din metoda run() într-o buclă apelează metoda get a obiectului Market pentru a obține aceste produse. Metodele put și get ale clasei Market sunt sincronizate. Pentru a urmări prezența mărfurilor în clasa Market , verificăm valoarea variabilei articol. Metoda get() pentru obținerea unui produs ar trebui să se declanșeze numai dacă există cel puțin un produs. Prin urmare, în metoda get, verificăm dacă produsul lipsește. Dacă articolul nu este disponibil, este apelată metoda wait() . Această metodă eliberează monitorul obiectului Market și blochează metoda get până când notify()metoda este apelată pe același monitor. Când un element este adăugat în metoda put() și este apelat notify() , metoda get() primește monitorul. După aceea, clientul nostru primește un articol. Pentru a face acest lucru, este afișat un mesaj, iar valoarea articolului este decrementată. În cele din urmă, apelul metodei notify() semnalează metodei put() să continue. În metoda put() funcționează o logică similară, doar că acum metoda put() ar trebui să funcționeze dacă nu există mai mult de 6 produse pe piață .

class Market {

   private int item = 0;

   public synchronized void get() {
       //here we use wait() method
       while (item < 1) {
           try {
               wait();
           }
           catch (InterruptedException e) {
           }
       }
       item--;
       System.out.println("A client has bought 1 item...");
       System.out.println("Items quantity in Market warehouse... " + item);
       notify();
   }

   public synchronized void put() {
       //here we use wait() method when the Warehouse is full
       while (item >= 6) {
           try {
               wait();
           }
           catch (InterruptedException e) {
           }
       }
       item ++;
       System.out.println("Manufacturer has added 1 more item...");
       System.out.println("Now there are " + item + " items in Warehouse" );
       notify();
   }
}

class Manufacturer implements Runnable {

   Market market;

   Manufacturer(Market market) {
       this.market = market;
   }


   public void run() {
       for (int i = 0; i < 8; i++) {
           market.put();
       }
   }
}

class Client implements Runnable {

   Market market;
   Client(Market market) {
       this.market = market;
   }
   public void run() {
       for (int i = 0; i < 8; i++) {
           market.get();
       }
   }
}
//wait() method test class
public class WaitTest {
   public static void main(String[] args) {

       Market market = new Market();
       Manufacturer manufacturer = new Manufacturer(market);
       Client client = new Client(market);
       new Thread(manufacturer).start();
       new Thread(client).start();
   }
}
Aici, folosind wait() în metoda get() , așteptăm ca Producătorul să adauge un nou articol. Și după adăugare, sunăm notify() , ca și cum ar fi să spunem că un loc a devenit liber în Warehouse și puteți adăuga mai multe. În metoda put() , folosind wait() , așteptăm eliberarea spațiului pe Warehouse . După ce spațiul este liber, adăugăm articolul, notify() începe firul și Clientul poate ridica articolul. Iată rezultatul programului nostru:
Producătorul a adăugat încă 1 articol... Acum există 1 articole în Warehouse Producătorul a adăugat încă 1 articol... Acum există 2 articole în Warehouse Producătorul a adăugat încă 1 articol... Acum există 3 articole în Warehouse Producătorul a adăugat a adăugat încă 1 articol... Acum sunt 4 articole în Warehouse Producătorul a adăugat încă 1 articol... Acum sunt 5 articole în Warehouse Producătorul a adăugat încă 1 articol... Acum există 6 articole în Warehouse Un client a cumpărat 1 articol... Cantitatea articolelor din depozitul Market... 5 Un client a cumpărat 1 articol... Cantitatea articolelor din depozitul Market... 4 Un client a cumpărat 1 articol... Cantitatea articolelor din depozitul Market... 3 Un client a cumpărat 1 articol... Cantitatea articolelor din depozitul Market... 2 Un client a cumpărat 1 articol... Cantitatea articolelor din depozitul Market... 1 Un client a cumpărat 1 articol... Cantitatea articolelor din depozitul Market ...0 Producătorul a adăugat încă 1 articol... Acum există 1 articole în Depozit Producătorul a adăugat încă 1 articol... Acum există 2 articole în Depozit Un client a cumpărat 1 articol... Cantitatea de articole în depozitul Market... 1 Un client a cumpărat 1 articol... Cantitate articole în depozitul Market... 0 Proces terminat cu codul de ieșire 0