java:concurrency_intro

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:concurrency_intro [2015/03/24 13:03]
gthanos [Σταματώντας την εκτέλεση ενός νήματος μέσω της μεθόδου sleep()]
java:concurrency_intro [2016/02/26 11:15] (current)
Line 69: Line 69:
 } }
 </​code>​ </​code>​
 +
 +<WRAP center round 70% tip>
 +Ένα νήμα μπορεί να καλέσει την μέθοδο sleep() για να κοιμηθεί το ίδιο και όχι για να κοιμήσει κάποιο άλλο νήμα. Ακόμη και εάν καλέσει την sleep() για να κοιμήσει ένα άλλο νήμα αυτό που θα γίνει είναι να κοιμηθεί το νήμα που την κάλεσε.
 +</​WRAP>​
  
 ===== Επανενεργοποίηση ενός νήματος μέσω της μεθόδου interrupt() ===== ===== Επανενεργοποίηση ενός νήματος μέσω της μεθόδου interrupt() =====
  
-Μία διακοπή (interrupt) αποτελεί ένδειξη προς την διεργασία να σταματήσει να κάνει αυτό που ​+Μία διακοπή (interrupt) αποτελεί ένδειξη προς την διεργασία να σταματήσει να κάνει αυτό που ​κάνει και να εκκινήσει κάτι διαφορετικό ή να τερματίσει. Η java υποστηρίζει την μέθοδο [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​Thread.html#​interrupt()|Thread.interrupt()]] για την αποστολή ενός σήματος διακοπής σε ένα νήμα. Εάν ένα νήμα έχει καλέσει την sleep() η κλήση της interrupt() για το νήμα αυτό, θα το αφυπνίσει και θα παραχθεί ένα [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​InterruptedException.html|InterruptedException]] για το νήμα που κοιμόταν. Για τον λόγο αυτό, η κλήση της sleep() θα πρέπει να γίνεται πάντα μέσα σε ένα try/catch block της μορφής 
 + 
 +<code java> 
 +  try { 
 +    Thread.sleep(4000);​ 
 +  } catch (InterruptedException e) { 
 +    System.out.println(("​We'​ve been interrupted:​ no more messages."​);​ 
 +    return; 
 +  } 
 +</​code>​ 
 + 
 +Εάν ένα νήμα δεν καλεί κάποια μέθοδο που δημιουργεί [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​InterruptedException.html|InterruptedException]] και η εφαρμογή δουλεύει με interrupts, θα πρέπει περιοδικά να ελέγχει κατά πόσο υπάρχει κάποια σήμα διακοπής προς το συγκεκριμένο νήμα σε μία ανακύκλωση της μορφής 
 + 
 +<code java> 
 +for (int i = 0; i < inputs.length;​ i++) { 
 +    heavyCalc(inputs[i]);​ 
 +    if (Thread.interrupted()) { 
 +        throw new InterruptedException();​ 
 +    } 
 +
 +</​code>​ 
 + 
 +<WRAP center round 85% tip> 
 +Ο μηχανισμός διακοπής υλοποιείται χρησιμοποιώντας ένα εσωτερικό flag (boolean true/false) γνωστό ως interrupt status. H κλήση της Thread.interrupt() θέτει στην τιμή true αυτό το flag. Κάθε φορά που ένα νήμα ελέγχει αν έχει διακοπεί ή όχι (καλώντας τη στατική μέθοδο Thread.interrupted() ), το παραπάνω flag απενεργοποιείται λαμβάνοντας την τιμή false.  
 + 
 +Η μη στατική μέθοδος isInterrupted(),​ χρησιμοποιείται από ένα νήμα για να ενημερωθεί για την κατάσταση διακοπής του ιδίου νήματος ή ενός άλλου νήματος (εξαρτάται από το αντικείμενο που την καλεί),​ αλλά δεν αλλάζει την κατάσταση του flag διακοπής. 
 +</​WRAP>​ 
 + 
 +===== Περιμένοντας ένα νήμα να ολοκληρώσει μέσω της μεθόδου join() ===== 
 + 
 +Η μέθοδος [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​Thread.html#​join()|join()]] επιτρέπει σε ένα νήμα να σταματήσει την εκτέλεση του έως ότου ένα άλλο νήμα να ολοκληρώσει την εκτέλεση του. Αν υποθέσουμε ότι ένα νήμα '​t'​ εκτελείται παράλληλα με το τρέχον νήμα, εάν το τρέχον νήμα καλέσει το παρακάτω 
 + 
 +<code java> 
 +  t.join(); 
 +</​code>​ 
 + 
 +τότε η εκτέλεση του σταματάει έως ότου το νήμα **'​t'​** να τερματίσει την εκτέλεση του. Υπάρχουν οι εξής παραλλαγές της μεθόδου join 
 +  * **t.join():​** περίμενε μέχρι το νήμα t να τερματίσει 
 +  * **t.join(long millis):** μέχρι το νήμα t να τερματίσει ή περίμενε για **millis** milliseconds. 
 +  * **t.join(long millis, int nanos):** μέχρι το νήμα t να τερματίσει ή περίμενε για **millis+nanos/​1000000** milliseconds. 
 + 
 +Όπως και η μέθοδος **sleep()** η μέθοδος **join()** δύναται να διακοπεί από ένα [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​InterruptedException.html|InterruptedException()]]. 
 + 
 +===== Εφαρμόζοντας τις μεθόδους sleep()/​interrupt()/​join() σε ένα παράδειγμα ===== 
 + 
 +Δείτε το παρακάτω παράδειγμα εκτέλεσης δύο νημάτων,​ το οποίο χρησιμοποιεί τις μεθόδους sleep(), interrupt() και join(). Το κεντρικό νήμα (μέθοδος main) περιμένει το νήμα που δημιουργείται για δεδομένο χρονικό διάστημα. Κάθε 1 δευτερόλεπτο το κεντρικό νήμα επιστρέφει από την μέθοδο **join(1000)** και εξετάζει εάν a)ο χρόνος εκτέλεσης του ολοκληρώθηκε και b) το παιδί τελείωσε μέσω της **t.isAlive()**. Εάν ισχύουν και οι δύο παραπάνω προϋποθέσεις τότε στέλνει ένα interrupt στο παιδί και περιμένει έως ότου αυτό να τερματίσει μέσω της **t.join()**. Στην συνέχεια ολοκληρώνει και το κεντρικό νήμα την εκτέλεση του. 
 + 
 +<code java MessageLoops.java>​ 
 +public class MessageLoop implements Runnable { 
 +  public void run() { 
 +    String importantInfo[] = { 
 +      "Mares eat oats",​ 
 +      "Does eat oats",​ 
 +      "​Little lambs eat ivy",​ 
 +      "A kid will eat ivy too" 
 +    }; 
 +    try { 
 +      for (int i = 0; 
 +        i < importantInfo.length;​ 
 +        i++) { 
 +        // Pause for 4 seconds 
 +        Thread.sleep(4000);​ 
 +        // Print a message 
 +        SimpleThreads.threadMessage(importantInfo[i]);​ 
 +      } 
 +    } catch (InterruptedException e) { 
 +      SimpleThreads.threadMessage("​I wasn't done!"​);​ 
 +    } 
 +  } 
 +
 +</​code>​ 
 + 
 +<code java SimpleThreads.java>​ 
 +public class SimpleThreads { 
 + 
 +  // Display a message, preceded by 
 +  // the name of the current thread 
 +  public static void threadMessage(String message) { 
 +    String threadName = 
 +      Thread.currentThread().getName();​ 
 +    System.out.format("​%s:​ %s%n",​ 
 +              threadName,​ 
 +              message); 
 +  }   
 + 
 +  public static void main(String args[]) 
 +    throws InterruptedException { 
 + 
 +    // Delay, in milliseconds before 
 +    // we interrupt MessageLoop 
 +    // thread (default one hour). 
 +    long patience = 1000 * 60 * 60; 
 + 
 +    // If command line argument 
 +    // present, gives patience 
 +    // in seconds. 
 +    if (args.length > 0) { 
 +      try { 
 +        patience = Long.parseLong(args[0]) * 1000; 
 +      } catch (NumberFormatException e) { 
 +        System.err.println("​Argument must be an integer."​);​ 
 +        System.exit(1);​ 
 +      } 
 +    } 
 + 
 +    threadMessage("​Starting MessageLoop thread"​);​ 
 +    long startTime = System.currentTimeMillis();​ 
 +    Thread t = new Thread(new MessageLoop());​ 
 +    t.start();​ 
 + 
 +    threadMessage("​Waiting for MessageLoop thread to finish"​);​ 
 +    // loop until MessageLoop 
 +    // thread exits 
 +    while (t.isAlive()) { 
 +      threadMessage("​Still waiting..."​);​ 
 +      // Wait maximum of 1 second 
 +      // for MessageLoop thread 
 +      // to finish. 
 +      t.join(1000);​ 
 +      if (((System.currentTimeMillis() - startTime) > patience) 
 +          && t.isAlive()) { 
 +        threadMessage("​Tired of waiting!"​);​ 
 +        t.interrupt();​ 
 +        // Shouldn'​t be long now 
 +        // -- wait indefinitely 
 +        t.join(); 
 +      } 
 +    } 
 +    threadMessage("​Finally!"​);​ 
 +  } 
 +}</​code>​ 
 + 
  
  
  
  
java/concurrency_intro.1427202200.txt.gz · Last modified: 2016/02/26 11:15 (external edit)