java:thread_signalling

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
java:thread_signalling [2015/04/18 17:11]
gthanos [Συγχρονισμός μέσω διαμοιραζόμενων αντικειμένων και διαρκούς επανάληψης]
java:thread_signalling [2016/02/26 11:15] (current)
Line 1: Line 1:
 ====== Συγχρονισμός Νημάτων ====== ====== Συγχρονισμός Νημάτων ======
  
-Ο συγχρονισμός νημάτων έχει σαν στόχο να επιτρέπει σε διαφορετικά νήματα να διαβάζουν ή να γράφουν με ασφάλεια σε διαμοιραζόμενες μεταβλητές χωρίς να προκύπτουν ασάφειες ως προς τις τιμές των μεταβλητών αυτών λόγω ταυτόχρονης μεταβολής τους. Ας υποθέσουμε ότι έχουμε δύο νήματα Α, Β και το νήμα Α θέλει να ειδοποιήσει το νήμα Β μόλις ολοκληρώσει την επεξεργασία των δεδομένων του, ώστε εκείνο να ξεκινήσει την επεξεργασία των δεδομένων.+Ο συγχρονισμός νημάτων έχει σαν στόχο να επιτρέπει σε διαφορετικά νήματα να διαβάζουν ή να γράφουν με ασφάλεια σε διαμοιραζόμενες μεταβλητές χωρίς να προκύπτουν ασάφειες ως προς τις τιμές των μεταβλητών αυτών λόγω ταυτόχρονης μεταβολής τους. ​Ο προσεκτικός αναγνώστης θα παρατηρήσει ότι το παραπάνω μπορούμε να το επιτύχουμε και με την χρήση συγχρονισμένων μπλοκ ή συγχρονισμένων μεθόδων. Το παραπάνω είναι εν μέρη σωστό, μόνο αν τα νήματα δύναται να εκτελούνται παράλληλα. Εάν τα νήματα δεν μπορούν να εκτελεστούν παράλληλα,​ αλλά το ένα νήμα θα πρέπει να περιμένει το άλλο να ολοκληρώσει τότε τα συγχρονισμένα block από μόνα τους δεν αποτελούν λύση. Σε αυτή την περίπτωση απαιτείται η έννοια της κλειδαριάς (lock).  
 + 
 +Ας υποθέσουμε ότι έχουμε δύο νήματα Α, Β και το νήμα Α θέλει να ειδοποιήσει το νήμα Β μόλις ολοκληρώσει την επεξεργασία των δεδομένων του, ώστε εκείνο να ξεκινήσει την επεξεργασία των δεδομένων ​που δημιουργήθηκαν. Δεν μας αρκεί δηλαδή τα νήματα Α, Β να εκτελούνται παράλληλα,​ αλλά θα θέλαμε το Β να ξεκινήσει την επεξεργασία μόλις το Α ολοκληρώσει.
  
 ===== Συγχρονισμός μέσω διαμοιραζόμενων αντικειμένων και διαρκούς επανάληψης ===== ===== Συγχρονισμός μέσω διαμοιραζόμενων αντικειμένων και διαρκούς επανάληψης =====
Line 10: Line 12:
 public class MySignal{ public class MySignal{
  
-  protected ​int dataToProcess = -1;+  protected ​boolean ​dataToProcess = true;
  
-  public synchronized ​int hasDataToProcess(){+  public synchronized ​boolean ​hasDataToProcess(){
     return dataToProcess;​     return dataToProcess;​
   }   }
  
-  public synchronized void setHasDataToProcess(int hasData){+  public synchronized void setHasDataToProcess(boolean ​hasData){
     this.dataToProcess = hasData;  ​     this.dataToProcess = hasData;  ​
   }   }
Line 22: Line 24:
 </​code>​ </​code>​
  
-Η παραπάνω κλάση μπορεί να χρησιμοποιηθεί για την επικοινωνία μεταξύ δύο νημάτων Α, Β. Ας υποθέσουμε ότι το νήμα **Β** περιμένει έως ότου τα δεδομένα να είναι διαθέσιμα από το νήμα **Α**, περιμένοντας διαρκώς σε ένα while() βρόγχο ​(loop), όπως παρακάτω+Η παραπάνω κλάση μπορεί να χρησιμοποιηθεί για την επικοινωνία μεταξύ δύο νημάτων ​**Α****Β**. Ας υποθέσουμε ότι το νήμα **Β** περιμένει έως ότου τα δεδομένα να είναι διαθέσιμα από το νήμα **Α**, περιμένοντας διαρκώς σε ένα while() βρόγχο,​ όπως παρακάτω:
  
 <code java BusyWait.java>​ <code java BusyWait.java>​
Line 43: Line 45:
   public void run() {   public void run() {
     try {     try {
-      ​Thread.sleep( new Random(new Date().getTime()).nextInt(1000) ); +      while(signal.hasDataToProcess() == false) {
-      ​while(signal.hasDataToProcess() ​!1) { +
-        if( signal.hasDataToProcess() ​== -1 ) { +
-          signal.setHasDataToProcess(0);​ +
-          break; +
-        }+
       }       }
-      signal.setHasDataToProcess(0);+      signal.setHasDataToProcess(false);   ​
       int i;       int i;
       for(i=0; i<10; i++) {       for(i=0; i<10; i++) {
Line 56: Line 53:
         System.out.println(Thread.currentThread().getName()+"​ iteration: "+i);         System.out.println(Thread.currentThread().getName()+"​ iteration: "+i);
       }       }
-      signal.setHasDataToProcess(1);+      signal.setHasDataToProcess(true); 
 +      System.out.println("​Exiting!"​);
     }     }
     catch(InterruptedException ex) {     catch(InterruptedException ex) {
Line 62: Line 60:
     }     }
   }   }
 +
 } }
 </​code>​ </​code>​
-Στο παράδειγμα αυτό το νήμα περιμένει,​ αλλά παράλληλα παραμένει και ενεργό (busy). ​+Στο παράδειγμα αυτό το νήμα περιμένει,​ αλλά παράλληλα παραμένει και ενεργό (busy). Επίσης,​ θα παρατηρήσετε ότι με σημαντική πιθανότητα (αλλά όχι σίγουρα) τα δύο νήματα θα εκκινήσουν ταυτόχρονα και ταυτόχρονα διαβάσουν την τιμή **signal.hasDataToProcess() -> -1**  και θα αρχίσουν να εκτελούνται παράλληλα πράγμα που δεν το θέλουμε.
  
 ===== Συγχρονισμός με χρήση wait(), notify(), notifyAll() ===== ===== Συγχρονισμός με χρήση wait(), notify(), notifyAll() =====
  
-Το παραπάνω σχήμα ​αν και ​είναι αποτελεσματικό ως προς τον συγχρονισμό δαπανά πολλά resources καθώς το νήμα Β παραμένει ενεργό περιμένοντας. Θα ήταν πιο αποδοτικό αν αντί να παραμένει ενεργό το νήμα Β //"​κοιμόταν"//​ περιμένοντας το νήμα Α να ολοκληρώσει. Η Java διαθέτει ένα μηχανισμό προκειμένου να επιτρέψει σε νήματα να κοιμηθούν περιμένοντας τα νήματα που εκτελούνται να ολοκληρώσουν το έργο τους. Συγκεκριμένα διαθέτει τρεις μεθόδους που επιτρέπουν το συγκεκριμένο συγχρονισμό [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​wait--|wait()]],​ [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​notify--|notify()]],​ [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​notifyAll--|notifyAll()]].+Το παραπάνω σχήμα ​δεν είναι αποτελεσματικό ως προς τον συγχρονισμό ​και επίσης ​δαπανά πολλά resources καθώς το νήμα ​**Β** παραμένει ενεργό περιμένοντας. Θα ήταν πιο αποδοτικό αν αντί να παραμένει ενεργό το νήμα ​**Β** //"​κοιμόταν"//​ περιμένοντας το νήμα ​**Α** να ολοκληρώσει. Η Java διαθέτει ένα μηχανισμό προκειμένου να επιτρέψει σε νήματα να κοιμηθούν περιμένοντας τα νήματα που εκτελούνται να ολοκληρώσουν το έργο τους. Συγκεκριμένα διαθέτει τρεις μεθόδους που επιτρέπουν το συγκεκριμένο συγχρονισμό [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​wait--|wait()]],​ [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​notify--|notify()]],​ [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​notifyAll--|notifyAll()]].
  
-Όταν ένα νήμα καλεί την μέθοδο //wait()// πάνω σε ένα αντικείμενο,​ τότε το νήμα κοιμάται έως ότου ένα άλλο νήμα καλέσει τη μέθοδο //​notify()//​ πάνω στο ίδιο αντικείμενο. Τότε το νήμα που κοιμόταν ξυπνάει και συνεχίζει την εκτέλεση του. ​Προκειμένου να κληθούν οι //wait()// και //​notify()//​ __το νήμα που τις καλεί ​θα πρέπει να λάβει το monitor lock για το συγκεκριμένο αντικείμενο__,​ δηλαδή τόσο η //wait()// όσο και η //​notify()//​ __θα πρέπει να κληθούν μέσα σε μία συγχρονισμένη μέθοδο ή συγχρονισμένο μπλοκ__. Δείτε το παρακάτω παράδειγμα συγχρονισμού με χρήση των //​wait()/​notify()//​.+Όταν ένα νήμα καλεί την μέθοδο //wait()// πάνω σε ένα αντικείμενο,​ τότε το νήμα κοιμάται έως ότου ένα άλλο νήμα καλέσει τη μέθοδο //​notify()//​ πάνω στο ίδιο αντικείμενο. Τότε το νήμα που κοιμόταν ξυπνάει και συνεχίζει την εκτέλεση του. ​Το νήμα που καλεί τις //wait()// και //​notify()//​ __θα πρέπει να λάβει το monitor lock για το συγκεκριμένο αντικείμενο__,​ δηλαδή τόσο η //wait()// όσο και η //​notify()//​ __θα πρέπει να κληθούν μέσα σε μία συγχρονισμένη μέθοδο ή συγχρονισμένο μπλοκ__. Δείτε το παρακάτω παράδειγμα συγχρονισμού με χρήση των //​wait()/​notify()//​.
  
 <code java MonitorObject.java>​ <code java MonitorObject.java>​
Line 81: Line 80:
  
   MonitorObject myMonitorObject = new MonitorObject();​   MonitorObject myMonitorObject = new MonitorObject();​
 +  boolean wasSignalled = false;
  
   public void doWait(){   public void doWait(){
     synchronized(myMonitorObject){     synchronized(myMonitorObject){
-      ​try+      ​if(!wasSignalled)
-        myMonitorObject.wait();​ +        ​try{ 
-      } catch(InterruptedException e){...}+          ​myMonitorObject.wait();​ 
 +         ​} catch(InterruptedException e){...} 
 +      } 
 +      //clear signal and continue running. 
 +      wasSignalled = false;
     }     }
   }   }
Line 92: Line 96:
   public void doNotify(){   public void doNotify(){
     synchronized(myMonitorObject){     synchronized(myMonitorObject){
 +      wasSignalled = true;
       myMonitorObject.notify();​       myMonitorObject.notify();​
     }     }
Line 98: Line 103:
 </​code>​ </​code>​
  
-Η μέθοδος //​notify()//​ ξυπνάει ένα νήμα που περιμένει στο συγκεκριμένο //monitor lock//. Όπως βλέπετε οι μέθοδοι //wait()// και //​notify()//​ καλούνται μέσα σε ένα συγχρονισμένο block του οποίου το //monitor lock// αφορά το αντικείμενο από το οποίο καλούνται οι //wait()// και //​notify()//​. Το παραπάνω σχήμα είναι υποχρεωτικό,​ δηλαδή ​+Η μέθοδος //​notify()//​ ξυπνάει ένα νήμα που περιμένει στο συγκεκριμένο //monitor lock//. Όπως βλέπετε οι μέθοδοι //wait()// και //​notify()//​ καλούνται μέσα σε ένα συγχρονισμένο block του οποίου το //monitor lock// αφορά το αντικείμενο από το οποίο καλούνται οι //wait()// και //​notify()//​. Το παραπάνω σχήμα είναι υποχρεωτικό,​ δηλαδή ​(ισχύουν και τα δύο παρακάτω):​
   - οι //wait()// και //​notify()//​ θα πρέπει να κληθούν μέσα σε ένα συγχρονισμένο block ή μία συγχρονισμένη μέθοδο. Αν δεν γίνει αυτό τότε λαμβάνουμε ένα [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​IllegalMonitorStateException.html|IllegalMonitorStateException]].   - οι //wait()// και //​notify()//​ θα πρέπει να κληθούν μέσα σε ένα συγχρονισμένο block ή μία συγχρονισμένη μέθοδο. Αν δεν γίνει αυτό τότε λαμβάνουμε ένα [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​IllegalMonitorStateException.html|IllegalMonitorStateException]].
-  - δεν μπορούμε να αποκτήσουμε το monitor lock ενός διαφορετικού αντικειμένου από αυτό με το οποίο καλούμε τις wait()/​notify(). Επίσης, βλέπετε ότι ​οι //wait()// και //​notify()//​ βρίσκονται μέσα σε ένα block. ​+  - Κατά την κλήση των //​wait()/​notify()// ​δεν μπορούμε να αποκτήσουμε το monitor lock ενός διαφορετικού αντικειμένου από αυτό με το οποίο καλούμε τις wait()/​notify(), δηλ δεν μπορούμε ​να κάνουμε κάτι ​σαν ​το παρακάτω
  
-Επίσης,​ εκτός της //notify()// υπάρχει και η //notifyAll()// που ξυπνάει όλα τα νήματα που περιμένουν στο συγκεκριμένο //monitor lock// σε αντίθεση με την notify() που ξυπνάει μόνο ένα νήμαΌταν περισσότερα του ενός νήματα περιμένουν το ποιο νήμα θα ξυπνήσει η //notify()// δεν ελέγχεται από εσάς.+<code java> 
 +  public void doWait()
 +    synchronized(myMonitorObject)
 +      if(!wasSignalled)
 +        try{ 
 +          myMonitorObject2.wait()
 +         } catch(InterruptedException e){...} 
 +      } 
 +      ​//clear signal and continue running. 
 +      wasSignalled = false; 
 +    } 
 +  } 
 +</​code>​
  
-Πως ​όμως το παραπάνω σχήμα ​είναι δυνατόν; Το thread ​που περιμένει ​δεν κρατά το monitor lock που έχει λάβει για το αντικείμενο ​myMonitorObject,​ όσο αυτό παραμένει μέσα στο synchronized block; Η απάντηση ​είναι αρνητική. Όσο το νήμα περιμένει ελευθερώνει το συγκεκριμένο monitor lock. Το παραπάνω επιτρέπει σε άλλες μεθόδους που ​δεν έχουν ​το lock να λάβουν ​το lock μπαίνοντας σε ένα συγχρονισμένο block ή συγχρονισμένη συνάρτηση και να καλέσουν τις //wait()// και //​notify()// ​μέσα από εκεί.+Εκτός της //​notify()//​ υπάρχει και η //​notifyAll()//​ που ξυπνάει όλα τα νήματα ​που περιμένουν στο συγκεκριμένο //monitor lock// σε αντίθεση με την notify() που ξυπνάει μόνο ​ένα νήμα. Όταν περισσότερα ​του ενός ​νήματα περιμένουν το ποιο νήμα θα ξυπνήσει η μέθοδος ​//​notify()// ​δεν ​ελέγχεται από εσάς. Είστε όμως σίγουροι ​ότι θα ξυπνήσει ένα νήμα.
  
-Όταν ένα νήμα ξυπνήσει δεν μπορεί ​αμέσως ​να βγει από την μέθοδο //wait()//. Αντίθετα θα πρέπει να περιμένει μέχρι το νήμα που κάλεσε την //​notify()//​ να βγει από ​το συγχρονισμένο block ή την συγχρονισμένη μέθοδο. ​ Αυτό συμβαίνει διότι το νήμα που ξυπνάει θα πρέπει να λάβει το //lock// του ​αντικειμένου ​από το οποίο κλήθηκε η μέθοδος //wait()// καθώς αυτή καλείτε πάντα μέσα σε ένα συγχρονισμένο block ή μία συγχρονισμένη μέθοδο. Σε αναλογία,​ αν πολλαπλά νήματα ξυπνήσουν μέσα από μία κλήση ​της //notifyAll()//, τότε αυτά τα νήματα δεν μπορούν να ξυπνήσουν όλα μαζί, αλλά ένα-ένα καθώς κάθε ένα νήμα που ξυπνάει θα πρέπει να λάβει ​το lock πάνω στο οποίο περιμένει πριν συνεχίσει την εκτέλεση του.+<WRAP important 80% round center>​ 
 +Ο παραπάνω κώδικας ​δεν μπορεί να εξασφαλίσει τον συγχρονισμό αν αντικαταστήσουμε την notify() ​με την notifyAll(). Γιατί
 +</​WRAP>​
  
-===== Χαμένα σήματα συγχρονισμού =====+Πως όμως το παραπάνω σχήμα είναι δυνατόν;​ Το thread που περιμένει δεν κρατά το monitor lock που έχει λάβει για το αντικείμενο myMonitorObject,​ όσο αυτό παραμένει μέσα στο συγχρονισμένο block ή την συγχρονισμένη μέθοδο;​ Η απάντηση είναι αρνητική. Όσο το νήμα περιμένει ελευθερώνει το συγκεκριμένο monitor lock. Το παραπάνω επιτρέπει σε άλλα νήματα που δεν έχουν το lock να λάβουν το lock μπαίνοντας σε ένα συγχρονισμένο block ή συγχρονισμένη συνάρτηση.  
 + 
 +<WRAP tip 80% round center>​ 
 +Στην πραγματικότητα αυτό που συμβαίνει είναι λίγο πιο πολύπλοκο από όσο περιγράφεται παραπάνω. Όταν ένα νήμα ξυπνήσει δεν μπορεί αμέσως να βγει από την μέθοδο //wait()//. Αντίθετα θα πρέπει να περιμένει μέχρι το νήμα που κάλεσε την //​notify()//​ να βγει από το συγχρονισμένο block ή την συγχρονισμένη μέθοδο. Αυτό συμβαίνει διότι το νήμα που ξυπνάει θα πρέπει να λάβει το //lock// του αντικειμένου από το οποίο κλήθηκε η μέθοδος //wait()// καθώς αυτή καλείται πάντα μέσα σε ένα συγχρονισμένο block ή μία συγχρονισμένη μέθοδο. Σε αναλογία,​ αν πολλαπλά νήματα ξυπνήσουν μέσα από μία κλήση της //​notifyAll()//,​ τότε αυτά τα νήματα δεν μπορούν να ξυπνήσουν όλα μαζί, αλλά ένα-ένα καθώς κάθε ένα νήμα που ξυπνάει θα πρέπει να λάβει το lock πάνω στο οποίο περιμένει πριν συνεχίσει την εκτέλεση του. 
 +</​WRAP>​ 
 + 
 +===== Ξαφνικά ξυπνήματα (Spurious wake-ups) ​=====
  
-Στο ​παραπάνω παράδειγμα η μέθοδος //doWait()// δεν ελέγχει εάν έχει έρθει ένα σήμα ή όχι ​πριν πάει για ύπνο το νήμα που την ​καλεί. Αν ένα σήμα ​έρθει πριν εκείνη κοιμηθεί ​δεν έχει τρόπο να ελέγξει αν το σήμα ​έφτασε ​ή όχι. Για τον λόγο αυτό ​χρησιμοποιούμε μία επιπλέον boolean ​μεταβλητή που ​κρατά την πληροφορία κατά πόσο δημιουργήθηκε ένα σήμα ή όχι. Ο παραπάνω κώδικας αναμορφώνεται ως εξής:+Υπάρχει η πιθανότητα ένα νήμα να ξυπνήσει ακόμη και ​δίχως να κληθεί η //notify()// ή η //​notifyAll()//​. Αν και οι περιπτώσεις αυτές δεν είναι συχνές δεν θα πρέπει ​να αποκλειστούν. Σε αυτή την ​περίπτωση αν το νήμα ​λάβει το **lock** θα ξυπνήσει και θα συνεχίσει την εκτέλεση του δίχως ​να εξετάσει αν έχει έρθει ένα ​σήμα ή όχι. Για το λόγο αυτό, καλό θα είναι ο έλεγχος ​που γίνεται παραπάνω (μέσα στην //if()//) να αντικατασταθεί με ένα while() loop ώστε να είμαστε σίγουροι ότι όσο δεν έχει έρθει ​κάποιο ​σήμα το νήμα που περιμένει δεν θα συνεχίσει την εκτέλεση τουΔείτε τον τελικό ​κώδικα ​παρακάτω
  
 <code java MyWaitNotify2.java>​ <code java MyWaitNotify2.java>​
Line 120: Line 145:
   public void doWait(){   public void doWait(){
     synchronized(myMonitorObject){     synchronized(myMonitorObject){
-      ​if(!wasSignalled){+      ​while(!wasSignalled){
         try{         try{
           myMonitorObject.wait();​           myMonitorObject.wait();​
Line 138: Line 163:
 } }
 </​code>​ </​code>​
-===== Ξαφνικά ξυπνήματα (Spurious wake-ups) ===== 
  
-Υπάρχει η πιθανότητα ένα νήμα ​να ξυπνήσε ακόμη και δίχως να κληθεί η //​notify()//​ ή η //​notifyAll()//​. Σε αυτή την περίπτωση αν το νήμα λάβει το lock θα ξυπνήσει και ​θα συνεχίσει την εκτέλεση του ​δίχως ​να εξετάσει αν έχει έρθει ένα ​σήμα ή όχι. Για το λόγο αυτόκαλό ​θα είναι ο έλεγχος που γίνεται παραπάνω (μέσα στην //if()//) να αντικατασταθεί με ένα ​while() loop ώστε να είμαστε σίγουροι ότι όσο δεν έχει έρθει κάποιο σήμα το νήμα ​που ​περιμένει δεν θα συνεχίσει την ​εκτέλεση του. Δείτε τον τελικό κώδικα παρακάτω +<WRAP info 80% center round> 
-<code java MyWaitNotify3.java> +Το παραπάνω σχήμα δουλεύει επίσης πολύ καλά εάν πολλαπλά νήματα περιμένουν σε ένα monitor lock.  
-public class MyWaitNotify3{+Αν τα νήματα αυτά ​ξυπνούν μέσα από μία κλήση της μεθόδου ​//​notifyAll()//​, τότε μέσα από ​τον παραπάνω κώδικα μόνο ένα από τα νήματα θα λάβει το monitor ​lock (το πρώτο που ​ξύπνησε και έλαβε το lock του ​αντικειμένου myMonitorObject). Τα υπόλοιπα, όταν με την σειρά ​τους θα λάβουν το lock, θα ελέγξουν ​την τιμή της μεταβλητής //​wasSignalled//​ και θα πάνε πάλι για ύπνο εφόσον την ​βρουν ίση με //false//
 +</​WRAP>​ 
 + 
 +Παρατηρήστε ότι η κλάση **MyWaitNotify2** υλοποιεί ένα ​μία απλή κλειδαριά,​ όπου μόνο ένα νήμα μπορεί να πάρει την κλειδαριά, ενώ όλα τα υπόλοιπα νήματα περιμένουν. Μόλις ολοκληρώσει την επεξεργασία ελευθερώνει την κλειδαριά και ενημερώνει ένα από ​τα νήματα που περιμένουν να ξεκινήσει. Η παραπάνω ​κλάση θα μπορούσε να γραφεί ​και ως εξής: 
 + 
 +<code java SimpleLock.java> 
 +public class SimpleLock ​{
  
   MonitorObject myMonitorObject = new MonitorObject();​   MonitorObject myMonitorObject = new MonitorObject();​
   boolean wasSignalled = false;   boolean wasSignalled = false;
  
-  public void doWait(){+  public void lock(){
     synchronized(myMonitorObject){     synchronized(myMonitorObject){
       while(!wasSignalled){       while(!wasSignalled){
Line 159: Line 189:
   }   }
  
-  public void doNotify(){+  public void unlock(){
     synchronized(myMonitorObject){     synchronized(myMonitorObject){
       wasSignalled = true;       wasSignalled = true;
Line 167: Line 197:
 } }
 </​code>​ </​code>​
- 
-Το παραπάνω σχήμα δουλεύει επίσης πολύ καλά εάν πολλαπλά νήματα περιμένουν σε ένα monitor lock.  
-Αν τα νήματα αυτά ξυπνούν μέσα από μία κλήση της μεθόδου //​notifyAll()//,​ τότε μέσα από τον παραπάνω κώδικα μόνο ένα από τα νήματα θα λάβει το monitor lock (το πρώτο που ξύπνησε και έλαβε το lock του αντικειμένου myMonitorObject). Τα υπόλοιπα,​ όταν με την σειρά τους θα λάβουν το lock, θα ελέγξουν την τιμή της μεταβλητής //​wasSignalled//​ και θα πάνε πάλι για ύπνο εφόσον την βρουν ίση με //false//. 
- 
- 
  
java/thread_signalling.1429377096.txt.gz · Last modified: 2016/02/26 11:15 (external edit)