Εκμάθηση Multithreading σε Java με Πρόγραμμα & Παραδείγματα


Οποιαδήποτε εφαρμογή μπορεί να έχει πολλαπλές διεργασίες (στιγμιότυπα). Κάθε μία από αυτή τη διαδικασία μπορεί να αντιστοιχιστεί είτε ως ένα νήμα είτε ως πολλαπλά νήματα. Θα δούμε σε αυτό το σεμινάριο πώς να εκτελούμε πολλές εργασίες ταυτόχρονα και επίσης να μάθουμε περισσότερα για τα νήματα και syncΧρονισμός μεταξύ των νημάτων.

Σε αυτό το σεμινάριο Multithreading στην Java, θα μάθουμε:

Τι είναι το Single Thread;

Ένα μεμονωμένο νήμα στην Java είναι βασικά μια ελαφριά και η μικρότερη μονάδα επεξεργασίας. Η Java χρησιμοποιεί νήματα χρησιμοποιώντας μια «Κλάση Νημάτων».

Υπάρχουν δύο τύποι νημάτων - νήμα χρήστη και νήμα δαίμονας (τα νήματα daemon χρησιμοποιούνται όταν θέλουμε να καθαρίσουμε την εφαρμογή και χρησιμοποιούνται στο παρασκήνιο).

Όταν ξεκινά μια εφαρμογή για πρώτη φορά, δημιουργείται νήμα χρήστη. Αναρτήστε το, μπορούμε να δημιουργήσουμε πολλά νήματα χρηστών και νήματα δαίμονα.

Παράδειγμα μεμονωμένου νήματος:

package demotest;

public class GuruThread
{
       public static void main(String[] args) {
              System.out.println("Single Thread");
       }
}

Πλεονεκτήματα του απλού νήματος:

  • Μειώνει την επιβάρυνση της εφαρμογής καθώς εκτελείται ένα νήμα στο σύστημα
  • Επίσης, μειώνει το κόστος συντήρησης της εφαρμογής.

Τι είναι το Multithreading στην Java;

Πολλαπλών νημάτων στην Java είναι μια διαδικασία εκτέλεσης δύο ή περισσότερων νημάτων ταυτόχροναneoγια τη μέγιστη χρήση της CPU. Οι εφαρμογές πολλαπλών νημάτων εκτελούν δύο ή περισσότερα νήματα που εκτελούνται ταυτόχρονα. Ως εκ τούτου, είναι επίσης γνωστό ως Concurrency στην Java. Κάθε νήμα τρέχει παράλληλα μεταξύ τους. Τα πολλαπλά νήματα δεν εκχωρούν ξεχωριστή περιοχή μνήμης, επομένως εξοικονομούν μνήμη. Επίσης, η εναλλαγή περιβάλλοντος μεταξύ των νημάτων απαιτεί λιγότερο χρόνο.

Παράδειγμα πολλαπλών νημάτων:

package demotest;
public class GuruThread1 implements Runnable
{
       public static void main(String[] args) {
        Thread guruThread1 = new Thread("Guru1");
        Thread guruThread2 = new Thread("Guru2");
        guruThread1.start();
        guruThread2.start();
        System.out.println("Thread names are following:");
        System.out.println(guruThread1.getName());
        System.out.println(guruThread2.getName());
    }
    @Override
    public void run() {
    }
}

Πλεονεκτήματα του multithread:

  • Οι χρήστες δεν είναι αποκλεισμένοι επειδή τα νήματα είναι ανεξάρτητα και μπορούμε να εκτελέσουμε πολλαπλές operaκατά καιρούς
  • Ως εκ τούτου, τα νήματα είναι ανεξάρτητα, τα άλλα νήματα δεν θα επηρεαστούν εάν ένα νήμα πληροί μια εξαίρεση.

Κύκλος ζωής νήματος σε Java

Ο κύκλος ζωής ενός νήματος:

Κύκλος ζωής νήματος σε Java
Κύκλος ζωής νήματος σε Java

Υπάρχουν διάφορα στάδια του κύκλου ζωής του νήματος όπως φαίνεται στο παραπάνω διάγραμμα:

  1. Νέα
  2. Δυνατότητα εκτέλεσης
  3. Τρέξιμο
  4. Αναμονή
  5. Νεκρός
  1. Νέα: Σε αυτή τη φάση, το νήμα δημιουργείται χρησιμοποιώντας την κλάση "Thread class". Παραμένει σε αυτήν την κατάσταση μέχρι το πρόγραμμα ξεκινά το νήμα. Είναι επίσης γνωστό ως γεννημένο νήμα.
  2. Δυνατότητα εκτέλεσης: Σε αυτή τη σελίδα, το στιγμιότυπο του νήματος καλείται με μια μέθοδο έναρξης. Ο έλεγχος νήματος δίνεται στον προγραμματιστή για να ολοκληρώσει την εκτέλεση. Εξαρτάται από τον προγραμματιστή, αν θα τρέξει το νήμα.
  3. Τρέξιμο: Όταν το νήμα αρχίσει να εκτελείται, τότε η κατάσταση αλλάζει σε κατάσταση "τρέχοντας". Ο χρονοπρογραμματιστής επιλέγει ένα νήμα από το σύνολο νημάτων και αρχίζει να εκτελείται στην εφαρμογή.
  4. Αναμονή: Αυτή είναι η κατάσταση όταν ένα νήμα πρέπει να περιμένει. Καθώς υπάρχουν πολλά νήματα που εκτελούνται στην εφαρμογή, υπάρχει ανάγκη syncΧρονισμός μεταξύ των νημάτων. Ως εκ τούτου, ένα νήμα πρέπει να περιμένει, μέχρι να εκτελεστεί το άλλο νήμα. Επομένως, αυτή η κατάσταση αναφέρεται ως κατάσταση αναμονής.
  5. Νεκρός: Αυτή είναι η κατάσταση όταν το νήμα τερματίζεται. Το νήμα είναι σε κατάσταση λειτουργίας και μόλις ολοκληρώθηκε η επεξεργασία βρίσκεται σε "νεκρή κατάσταση".


Μερικές από τις μεθόδους που χρησιμοποιούνται συνήθως για νήματα είναι:

Μέθοδος Περιγραφή
αρχή() Αυτή η μέθοδος ξεκινά την εκτέλεση του νήματος και FMV καλεί τη μέθοδο run() στο νήμα.
Ύπνος (int χιλιοστά του δευτερολέπτου) Αυτή η μέθοδος κάνει το νήμα να κοιμάται, επομένως η εκτέλεση του νήματος θα σταματήσει για χιλιοστά του δευτερολέπτου που παρέχονται και μετά από αυτό, το νήμα αρχίζει ξανά να εκτελείται. Αυτή η βοήθεια σε syncΧρονισμός των νημάτων.
getName () Επιστρέφει το όνομα του νήματος.
setPriority (σε νέα προτεραιότητα) Αλλάζει την προτεραιότητα του νήματος.
απόδοση () Αναγκάζει το τρέχον νήμα να σταματήσει και άλλα νήματα να εκτελεστούν.

Παράδειγμα: Σε αυτό το πρόγραμμα πολλαπλών νημάτων στο παράδειγμα Java, θα δημιουργήσουμε ένα νήμα και θα εξερευνήσουμε ενσωματωμένες μεθόδους που είναι διαθέσιμες για νήματα.

package demotest;
public class thread_example1 implements Runnable {
    @Override
    public void run() {
    }
    public static void main(String[] args) {
        Thread guruthread1 = new Thread();
        guruthread1.start();
        try {
            guruthread1.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        guruthread1.setPriority(1);
        int gurupriority = guruthread1.getPriority();
        System.out.println(gurupriority);
        System.out.println("Thread Running");
  }
}

Επεξήγηση του κώδικα:

  • Κωδικός Γραμμή 2: Δημιουργούμε μια κλάση "thread_Example1" που υλοποιεί τη διεπαφή Runnable (θα πρέπει να υλοποιηθεί από οποιαδήποτε κλάση οι παρουσίες της οποίας προορίζονται να εκτελεστούν από το νήμα.)
  • Κωδικός Γραμμή 4: Αντικαθιστά τη μέθοδο εκτέλεσης της διεπαφής με δυνατότητα εκτέλεσης, καθώς είναι υποχρεωτική η παράκαμψη αυτής της μεθόδου
  • Κωδικός Γραμμή 6: Εδώ έχουμε ορίσει την κύρια μέθοδο με την οποία θα ξεκινήσουμε την εκτέλεση του νήματος.
  • Κωδικός Γραμμή 7: Εδώ δημιουργούμε ένα νέο όνομα νήματος ως "guruthread1" εγκαινιάζοντας μια νέα κατηγορία νήματος.
  • Κωδικός Γραμμή 8: θα χρησιμοποιήσουμε τη μέθοδο "start" του νήματος χρησιμοποιώντας την περίπτωση "guruthread1". Εδώ το νήμα θα ξεκινήσει να εκτελείται.
  • Κωδικός Γραμμή 10: Εδώ χρησιμοποιούμε τη μέθοδο "sleep" του νήματος χρησιμοποιώντας το παράδειγμα "guruthread1". Ως εκ τούτου, το νήμα θα κοιμάται για 1000 χιλιοστά του δευτερολέπτου.
  • Κωδικός 9-14: Εδώ έχουμε βάλει τη μέθοδο ύπνου στο μπλοκ try catch καθώς υπάρχει επιλεγμένη εξαίρεση που συμβαίνει, π.χ. Διακεκομμένη εξαίρεση.
  • Κωδικός Γραμμή 15: Εδώ ορίζουμε την προτεραιότητα του νήματος στο 1 από όποια προτεραιότητα ήταν
  • Κωδικός Γραμμή 16: Εδώ παίρνουμε την προτεραιότητα του νήματος χρησιμοποιώντας την getPriority()
  • Κωδικός Γραμμή 17: Εδώ εκτυπώνουμε την τιμή που ανακτήθηκε από το getPriority
  • Κωδικός Γραμμή 18: Εδώ γράφουμε ένα κείμενο που τρέχει το νήμα.

Όταν εκτελέσετε τον παραπάνω κώδικα, λαμβάνετε το ακόλουθοwing παραγωγή:

Παράδειγμα νήματος σε Java

Παραγωγή:

Το 5 είναι η προτεραιότητα του νήματος και το Thread Running είναι το κείμενο που είναι η έξοδος του κώδικά μας.

Νήμα Java Syncχρονισμός

Στην πολυνηματική, υπάρχει το αsyncσκληρή συμπεριφορά των προγραμμάτων. Εάν ένα νήμα εγγράφει ορισμένα δεδομένα και ένα άλλο νήμα που διαβάζει δεδομένα ταυτόχρονα, μπορεί να δημιουργήσει ασυνέπεια στην εφαρμογή.

Όταν υπάρχει ανάγκη πρόσβασης στους κοινόχρηστους πόρους από δύο ή περισσότερα νήματα, τότε syncχρησιμοποιείται η προσέγγιση χρονισμού.

Η Java έχει παράσχει syncεναρμονισμένες μεθόδους για εφαρμογή syncσυγχρονισμένη συμπεριφορά.

Σε αυτή την προσέγγιση, μόλις το νήμα φτάσει στο εσωτερικό του syncσυγχρονισμένο μπλοκ, τότε κανένα άλλο νήμα δεν μπορεί να καλέσει αυτήν τη μέθοδο στο ίδιο αντικείμενο. Όλα τα νήματα πρέπει να περιμένουν μέχρι να τελειώσει αυτό το νήμα syncχρονίζει το μπλοκ και βγαίνει από αυτό.

Με αυτόν τον τρόπο, το syncΤο hronization βοηθά σε μια εφαρμογή πολλαπλών νημάτων. Ένα νήμα πρέπει να περιμένει έως ότου το άλλο νήμα ολοκληρώσει την εκτέλεσή του μόνο τότε επιτρέπεται να εκτελεστούν τα άλλα νήματα.

Μπορεί να γραφτεί στο following μορφή:

Synchronized(object)
{  
        //Block of statements to be synchronized
}

Παράδειγμα Java Multithreading

Σε αυτό το παράδειγμα Java multithreading, θα πάρουμε δύο νήματα και θα φέρουμε τα ονόματα του νήματος.

Παράδειγμα 1:

GuruThread1.java
package demotest;
public class GuruThread1 implements Runnable{

    /**
     * @param args
     */
    public static void main(String[] args) {
        Thread guruThread1 = new Thread("Guru1");
        Thread guruThread2 = new Thread("Guru2");
        guruThread1.start();
        guruThread2.start();
        System.out.println("Thread names are following:");
        System.out.println(guruThread1.getName());
        System.out.println(guruThread2.getName());
    }
    @Override
    public void run() {
    }
}

Επεξήγηση του κώδικα:

  • Κωδικός Γραμμή 3: Έχουμε πάρει μια κλάση "GuruThread1" που υλοποιεί το Runnable (θα πρέπει να υλοποιηθεί από οποιαδήποτε κλάση της οποίας οι παρουσίες προορίζονται να εκτελεστούν από το νήμα.)
  • Κωδικός Γραμμή 8: Αυτή είναι η κύρια μέθοδος της τάξης
  • Κωδικός Γραμμή 9: Εδώ δημιουργούμε την κλάση Thread και δημιουργούμε ένα στιγμιότυπο με το όνομα "guruThread1" και δημιουργούμε ένα νήμα.
  • Κωδικός Γραμμή 10: Εδώ δημιουργούμε την κλάση Thread και δημιουργούμε ένα στιγμιότυπο με το όνομα "guruThread2" και δημιουργούμε ένα νήμα.
  • Κωδικός Γραμμή 11: Ξεκινάμε το νήμα, π.χ. guruThread1.
  • Κωδικός Γραμμή 12: Ξεκινάμε το νήμα, π.χ. guruThread2.
  • Κωδικός Γραμμή 13: Έξοδος του κειμένου ως "Τα ονόματα των νημάτων ακολουθούνwing: "
  • Κωδικός Γραμμή 14: Λήψη του ονόματος του νήματος 1 χρησιμοποιώντας τη μέθοδο getName() της κλάσης νήματος.
  • Κωδικός Γραμμή 15: Λήψη του ονόματος του νήματος 2 χρησιμοποιώντας τη μέθοδο getName() της κλάσης νήματος.

Όταν εκτελέσετε τον παραπάνω κώδικα, λαμβάνετε το ακόλουθοwing παραγωγή:

Παράδειγμα Java Multithreading

Παραγωγή:

Τα ονόματα των νημάτων εμφανίζονται εδώ ως

  • Guru1
  • Guru2

Παράδειγμα 2:

Σε αυτό το παράδειγμα multithreading στην Java, θα μάθουμε για τις μεθόδους παράκαμψης run() και start() μιας διεπαφής με δυνατότητα εκτέλεσης και θα δημιουργήσουμε δύο νήματα αυτής της κλάσης και θα τα εκτελέσουμε ανάλογα.

Επίσης, παρακολουθούμε δύο μαθήματα,

  • Ένα που θα υλοποιήσει τη διεπαφή με δυνατότητα εκτέλεσης και
  • Ένα άλλο που θα έχει την κύρια μέθοδο και θα εκτελείται ανάλογα.
package demotest;
public class GuruThread2 {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  GuruThread3 threadguru1 = new GuruThread3("guru1");
  threadguru1.start();
  GuruThread3 threadguru2 = new GuruThread3("guru2");
  threadguru2.start();
 }
}
class GuruThread3 implements Runnable {
 Thread guruthread;
 private String guruname;
 GuruThread3(String name) {
  guruname = name;
 }
 @Override
 public void run() {
  System.out.println("Thread running" + guruname);
  for (int i = 0; i < 4; i++) {
   System.out.println(i);
   System.out.println(guruname);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    System.out.println("Thread has been interrupted");
   }
  }
 }
 public void start() {
  System.out.println("Thread started");
  if (guruthread == null) {
   guruthread = new Thread(this, guruname);
   guruthread.start();
  }
 }
}

Επεξήγηση του κώδικα:

  • Κωδικός Γραμμή 2: Εδώ παίρνουμε μια κλάση "GuruThread2" που θα έχει την κύρια μέθοδο σε αυτήν.
  • Κωδικός Γραμμή 4: Εδώ παίρνουμε μια κύρια μέθοδο της τάξης.
  • Κωδικός Γραμμή 6-7: Εδώ δημιουργούμε μια παρουσία της κλάσης GuruThread3 (η οποία δημιουργείται στις παρακάτω γραμμές του κώδικα) ως "threadguru1" και ξεκινάμε το νήμα.
  • Κωδικός Γραμμή 8-9: Εδώ δημιουργούμε μια άλλη παρουσία της κλάσης GuruThread3 (η οποία δημιουργείται στις παρακάτω γραμμές του κώδικα) ως "threadguru2" και ξεκινάμε το νήμα.
  • Κωδικός Γραμμή 11: Εδώ δημιουργούμε μια κλάση "GuruThread3" που υλοποιεί τη διεπαφή με δυνατότητα εκτέλεσης (θα πρέπει να υλοποιηθεί από οποιαδήποτε κλάση της οποίας οι παρουσίες προορίζονται να εκτελεστούν από το νήμα.)
  • Κωδικός Γραμμή 13-14: Παίρνουμε δύο μεταβλητές κλάσης από τις οποίες η μία είναι της κλάσης τύπου thread και η άλλη της κλάσης string.
  • Κωδικός Γραμμή 15-18: παρακάμπτουμε τον κατασκευαστή GuruThread3, ο οποίος παίρνει ένα όρισμα ως τύπο συμβολοσειράς (που είναι το όνομα νημάτων) που εκχωρείται στη μεταβλητή κλάσης guruname και επομένως το όνομα του νήματος αποθηκεύεται.
  • Κωδικός Γραμμή 20: Εδώ παρακάμπτουμε τη μέθοδο run() της διεπαφής με δυνατότητα εκτέλεσης.
  • Κωδικός Γραμμή 21: Εξάγουμε το όνομα του νήματος χρησιμοποιώντας την πρόταση println.
  • Κωδικός Γραμμή 22-31: Εδώ χρησιμοποιούμε έναν βρόχο for με μετρητή αρχικοποιημένο στο 0, και δεν πρέπει να είναι μικρότερος από 4 (μπορούμε να πάρουμε οποιονδήποτε αριθμό, επομένως εδώ ο βρόχος θα τρέξει 4 φορές) και αυξάνοντας τον μετρητή. Εκτυπώνουμε το όνομα του νήματος και επίσης κάνουμε το νήμα να αδράνει για 1000 χιλιοστά του δευτερολέπτου μέσα σε ένα μπλοκ try-catch καθώς η μέθοδος ύπνου αυξάνει την επιλεγμένη εξαίρεση.
  • Κωδικός Γραμμή 33: Εδώ παρακάμπτουμε τη μέθοδο έναρξης της διεπαφής με δυνατότητα εκτέλεσης.
  • Κωδικός Γραμμή 35: Βγάζουμε το κείμενο "Το νήμα ξεκίνησε".
  • Κωδικός Γραμμή 36-40: Εδώ παίρνουμε μια συνθήκη if για να ελέγξουμε αν η μεταβλητή κλάσης guruthread έχει αξία ή όχι. Εάν είναι μηδενικό, τότε δημιουργούμε ένα στιγμιότυπο χρησιμοποιώντας κλάση νήματος που παίρνει το όνομα ως παράμετρο (τιμή για την οποία έχει εκχωρηθεί στον κατασκευαστή). Μετά από αυτό το νήμα ξεκινά χρησιμοποιώντας τη μέθοδο start().

Όταν εκτελέσετε τον παραπάνω κώδικα, λαμβάνετε το ακόλουθοwing παραγωγή:

Παράδειγμα πολλαπλών νημάτων σε Java

Παραγωγή:

Υπάρχουν δύο νήματα, επομένως, λαμβάνουμε δύο φορές το μήνυμα "Το νήμα ξεκίνησε".

Παίρνουμε τα ονόματα του νήματος όπως τα έχουμε βγάλει.

Μπαίνει στον βρόχο for όπου εκτυπώνουμε το όνομα του μετρητή και του νήματος και ο μετρητής ξεκινά με 0.

Ο βρόχος εκτελείται τρεις φορές και ενδιάμεσα το νήμα αδράνει για 1000 χιλιοστά του δευτερολέπτου.

Ως εκ τούτου, πρώτα, παίρνουμε guru1 μετά guru2 και μετά πάλι guru2 επειδή το νήμα κοιμάται εδώ για 1000 χιλιοστά του δευτερολέπτου και μετά τον επόμενο guru1 και ξανά τον guru1, το νήμα κοιμάται για 1000 χιλιοστά του δευτερολέπτου, οπότε παίρνουμε τον guru2 και μετά τον guru1.

Χαρακτηριστικά

Σε αυτό το σεμινάριο, είδαμε εφαρμογές πολλαπλών νημάτων σε Java και πώς να χρησιμοποιήσετε ένα και πολλαπλό νήμα στην Java.

  • Εξηγήστε το multithreading σε Java: στο multithreading, οι χρήστες δεν αποκλείονται καθώς τα νήματα είναι ανεξάρτητα και μπορούν να εκτελέσουν πολλαπλές operaθέσεις κατά τον χρόνο
  • Τα διάφορα στάδια του κύκλου ζωής του νήματος είναι,
    • Νέα
    • Δυνατότητα εκτέλεσης
    • Τρέξιμο
    • Αναμονή
    • Νεκρός
  • Μάθαμε και για syncχρονισμός μεταξύ νημάτων, που βοηθούν την εφαρμογή να λειτουργεί ομαλά.
  • Ο πολυνηματικός προγραμματισμός σε Java διευκολύνει πολλές περισσότερες εργασίες εφαρμογής.