Οποιαδήποτε εφαρμογή μπορεί να έχει πολλές διαδικασίες (παρουσίες). Κάθε μια από αυτές τις διαδικασίες μπορεί να αντιστοιχιστεί είτε ως ένα νήμα είτε ως πολλαπλά νήματα. Θα δούμε σε αυτό το σεμινάριο πώς να εκτελέσετε πολλές εργασίες ταυτόχρονα και επίσης να μάθουμε περισσότερα σχετικά με τα θέματα και τον συγχρονισμό μεταξύ των νημάτων.
Σε αυτό το σεμινάριο, θα μάθουμε:
- Τι είναι το μονό νήμα
- Τι είναι το Multithreading στην Java;
- Κύκλος ζωής νήματος στην Ιάβα
- Συγχρονισμός νήματος Java
- Παράδειγμα πολλαπλών νημάτων Java
Τι είναι το μονό νήμα;
Ένα μονό νήμα είναι βασικά ένα ελαφρύ και η μικρότερη μονάδα επεξεργασίας. Η Java χρησιμοποιεί νήματα χρησιμοποιώντας μια "Κλάση νημάτων".
Υπάρχουν δύο τύποι νήματος - νήμα χρήστη και νήμα δαίμονα (τα νήματα δαίμονα χρησιμοποιούνται όταν θέλουμε να καθαρίσουμε την εφαρμογή και χρησιμοποιούνται στο παρασκήνιο).
Όταν ξεκινά για πρώτη φορά μια εφαρμογή, δημιουργείται νήμα χρήστη. Δημοσιεύστε αυτό, μπορούμε να δημιουργήσουμε πολλά νήματα χρήστη και νήματα δαίμονα.
Παράδειγμα απλού νήματος:
demotest πακέτουδημόσια τάξη GuruThread{Δημόσιο στατικό κενό (String [] args) {System.out.println ("Μονό νήμα");}}
Πλεονεκτήματα ενός νήματος:
- Μειώνει τα γενικά έξοδα της εφαρμογής καθώς εκτελείται ένα νήμα στο σύστημα
- Επίσης, μειώνει το κόστος συντήρησης της εφαρμογής.
Τι είναι το Multithreading στην Java;
Το MULTITHREADING στην Java είναι μια διαδικασία εκτέλεσης δύο ή περισσότερων νημάτων ταυτόχρονα για τη μέγιστη αξιοποίηση της CPU. Οι εφαρμογές πολλαπλών νημάτων εκτελούν δύο ή περισσότερα νήματα που εκτελούνται ταυτόχρονα. Ως εκ τούτου, είναι επίσης γνωστό ως Concurrency στην Java. Κάθε νήμα τρέχει παράλληλα μεταξύ τους. Τα πολυμορφικά νήματα δεν διαθέτουν ξεχωριστή περιοχή μνήμης, επομένως εξοικονομούν μνήμη. Επίσης, η εναλλαγή περιβάλλοντος μεταξύ νημάτων απαιτεί λιγότερο χρόνο.
Παράδειγμα πολλαπλών νημάτων:
demotest πακέτουδημόσια τάξη GuruThread1 υλοποιεί το Runnable{Δημόσιο στατικό κενό (String [] args) {Νήμα γκουρούThread1 = νέο νήμα ("Guru1");Νήμα γκουρούThread2 = νέο νήμα ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Τα ονόματα των νημάτων είναι τα εξής:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Καταπατώδημόσια άκυρη εκτέλεση () {}}
Πλεονεκτήματα του multithread:
- Οι χρήστες δεν αποκλείονται επειδή τα νήματα είναι ανεξάρτητα και μπορούμε να εκτελούμε πολλές λειτουργίες κατά καιρούς
- Καθώς τα νήματα είναι ανεξάρτητα, τα άλλα νήματα δεν θα επηρεαστούν εάν ένα νήμα πληροί μια εξαίρεση.
Κύκλος ζωής νήματος στην Ιάβα
Ο κύκλος ζωής ενός νήματος:
Υπάρχουν διάφορα στάδια του κύκλου ζωής του νήματος όπως φαίνεται στο παραπάνω διάγραμμα:
- Νέος
- Τρέξιμο
- Τρέξιμο
- Αναμονή
- Νεκρός
- Νέο: Σε αυτήν τη φάση, το νήμα δημιουργείται χρησιμοποιώντας την κλάση "Κλάση νημάτων". Παραμένει σε αυτήν την κατάσταση μέχρι το πρόγραμμα να ξεκινήσει το νήμα. Είναι επίσης γνωστό ως γεννημένο νήμα.
- Runnable: Σε αυτήν τη σελίδα, η παρουσία του νήματος καλείται με μια μέθοδο εκκίνησης. Το νήμα ελέγχου δίνεται στον προγραμματιστή για να ολοκληρωθεί η εκτέλεση. Εξαρτάται από τον προγραμματιστή, αν θα εκτελεστεί το νήμα.
- Εκτέλεση: Όταν το νήμα αρχίζει να εκτελείται, τότε η κατάσταση αλλάζει σε κατάσταση "τρέξιμο". Ο προγραμματιστής επιλέγει ένα νήμα από το νήμα και αρχίζει να εκτελείται στην εφαρμογή.
- Αναμονή: Αυτή είναι η κατάσταση κατά την οποία ένα νήμα πρέπει να περιμένει. Καθώς εκτελούνται πολλά νήματα στην εφαρμογή, υπάρχει ανάγκη συγχρονισμού μεταξύ των νημάτων. Ως εκ τούτου, ένα νήμα πρέπει να περιμένει, μέχρι να εκτελεστεί το άλλο νήμα. Επομένως, αυτή η κατάσταση αναφέρεται ως κατάσταση αναμονής.
- Dead: Αυτή είναι η κατάσταση κατά την οποία το νήμα τερματίζεται. Το νήμα είναι σε κατάσταση λειτουργίας και μόλις ολοκληρωθεί η επεξεργασία βρίσκεται σε "νεκρή κατάσταση".
Μερικές από τις κοινώς χρησιμοποιούμενες μεθόδους για νήματα είναι:
Μέθοδος | Περιγραφή |
---|---|
αρχή() | Αυτή η μέθοδος ξεκινά την εκτέλεση του νήματος και η JVM καλεί τη μέθοδο run () στο νήμα. |
Ύπνος (εντός χιλιοστών του δευτερολέπτου) | Αυτή η μέθοδος κάνει το νήμα να τεθεί σε αναστολή, επομένως η εκτέλεση του νήματος θα σταματήσει για τα χιλιοστά του δευτερολέπτου που παρέχονται και μετά από αυτό, το νήμα αρχίζει ξανά να εκτελείται. Αυτό βοηθά στο συγχρονισμό των νημάτων. |
getName () | Επιστρέφει το όνομα του νήματος. |
setPriority (int newpriority) | Αλλάζει την προτεραιότητα του νήματος. |
απόδοση () | Προκαλεί την εκτέλεση του νήματος σε διακοπή και άλλα νήματα. |
Παράδειγμα: Σε αυτό το παράδειγμα θα δημιουργήσουμε ένα νήμα και θα διερευνήσουμε τις ενσωματωμένες μεθόδους που είναι διαθέσιμες για τα νήματα.
demotest πακέτουpublic class thread_example1 υλοποιεί Runnable {@Καταπατώδημόσια άκυρη εκτέλεση () {}Δημόσιο στατικό κενό (String [] args) {Νήμα guruthread1 = νέο νήμα ();guruthread1.start ();προσπαθήστε {guruthread1.sleep (1000);} αλίευση (InterruptException e) {// TODO Αυτόματο δημιουργημένο μπλοκ σύλληψης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: θα χρησιμοποιήσουμε τη μέθοδο "έναρξης" του νήματος χρησιμοποιώντας την παρουσία "guruthread1". Εδώ θα ξεκινήσει η εκτέλεση του νήματος.
- Γραμμή κώδικα 10: Εδώ χρησιμοποιούμε τη μέθοδο "ύπνου" του νήματος χρησιμοποιώντας την παρουσία "guruthread1". Ως εκ τούτου, το νήμα θα κοιμηθεί για 1000 χιλιοστά του δευτερολέπτου.
- Κωδικός 9-14: Εδώ έχουμε θέσει τη μέθοδο αναστολής στο try catch block, καθώς υπάρχει ελεγμένη εξαίρεση που συμβαίνει, δηλαδή Διακοπή εξαίρεσης.
- Γραμμή κώδικα 15: Εδώ ορίζουμε την προτεραιότητα του νήματος σε 1 από όποια προτεραιότητα ήταν
- Γραμμή κώδικα 16: Εδώ παίρνουμε την προτεραιότητα του νήματος χρησιμοποιώντας το getPriority ()
- Γραμμή κώδικα 17: Εδώ εκτυπώνουμε την τιμή που ανακτήθηκε από το getPriority
- Γραμμή κώδικα 18: Εδώ γράφουμε ένα κείμενο που εκτελείται το νήμα.
Όταν εκτελείτε τον παραπάνω κώδικα, λαμβάνετε την ακόλουθη έξοδο:
Παραγωγή:
Το 5 είναι η προτεραιότητα του νήματος και το Thread Running είναι το κείμενο που είναι το αποτέλεσμα του κώδικα μας.
Συγχρονισμός νήματος Java
Στο multithreading, υπάρχει η ασύγχρονη συμπεριφορά των προγραμμάτων. Εάν ένα νήμα γράφει ορισμένα δεδομένα και ένα άλλο νήμα που διαβάζει δεδομένα ταυτόχρονα, μπορεί να δημιουργήσει ασυνέπεια στην εφαρμογή.
Όταν υπάρχει ανάγκη πρόσβασης στους κοινόχρηστους πόρους με δύο ή περισσότερα νήματα, τότε χρησιμοποιείται προσέγγιση συγχρονισμού.
Η Java έχει παράσχει συγχρονισμένες μεθόδους για την εφαρμογή συγχρονισμένης συμπεριφοράς.
Σε αυτήν την προσέγγιση, όταν το νήμα φτάσει μέσα στο συγχρονισμένο μπλοκ, τότε κανένα άλλο νήμα δεν μπορεί να καλέσει αυτή τη μέθοδο στο ίδιο αντικείμενο. Όλα τα νήματα πρέπει να περιμένουν μέχρι το νήμα να ολοκληρώσει το συγχρονισμένο μπλοκ και να βγει από αυτό.
Με αυτόν τον τρόπο, ο συγχρονισμός βοηθά σε μια εφαρμογή πολλαπλών νημάτων. Ένα νήμα πρέπει να περιμένει έως ότου άλλο νήμα ολοκληρώσει την εκτέλεση του μόνο τότε τα άλλα νήματα επιτρέπονται για εκτέλεση.
Μπορεί να γραφτεί με την ακόλουθη μορφή:
Συγχρονισμένο (αντικείμενο){// Μπλοκ δηλώσεων προς συγχρονισμό}
Παράδειγμα πολλαπλών νημάτων Java
Σε αυτό το παράδειγμα, θα πάρουμε δύο νήματα και θα πάρουμε τα ονόματα του νήματος.
Παράδειγμα 1:
GuruThread1.javademotest πακέτουδημόσια τάξη GuruThread1 υλοποιεί το Runnable {/ *** Ο @param υποστηρίζει* /Δημόσιο στατικό κενό (String [] args) {Νήμα γκουρούThread1 = νέο νήμα ("Guru1");Νήμα γκουρούThread2 = νέο νήμα ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Τα ονόματα των νημάτων είναι τα εξής:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Καταπατώδημόσια άκυρη εκτέλεση () {}}
Επεξήγηση του κωδικού:
- Γραμμή κώδικα 3: Έχουμε λάβει μια τάξη "GuruThread1" που εφαρμόζει το Runnable (θα πρέπει να εφαρμοστεί από οποιαδήποτε τάξη των οποίων οι παρουσίες προορίζονται να εκτελεστούν από το νήμα.)
- Γραμμή κώδικα 8: Αυτή είναι η κύρια μέθοδος της τάξης
- Γραμμή κώδικα 9: Εδώ δημιουργούμε την τάξη του νήματος και δημιουργούμε μια παρουσία που ονομάζεται "guruThread1" και δημιουργούμε ένα νήμα.
- Γραμμή κώδικα 10: Εδώ δημιουργούμε την τάξη του νήματος και δημιουργούμε μια παρουσία που ονομάζεται "guruThread2" και δημιουργούμε ένα νήμα.
- Γραμμή κώδικα 11: Ξεκινάμε το νήμα, δηλαδή το guruThread1.
- Γραμμή κώδικα 12: Ξεκινάμε το νήμα, δηλαδή το guruThread2.
- Γραμμή κώδικα 13: Έξοδος του κειμένου ως "Τα ονόματα νημάτων είναι τα εξής:"
- Γραμμή κώδικα 14: Λήψη του ονόματος του νήματος 1 χρησιμοποιώντας τη μέθοδο getName () της κλάσης νήματος.
- Γραμμή κώδικα 15: Λήψη του ονόματος του νήματος 2 χρησιμοποιώντας τη μέθοδο getName () της κλάσης νήματος.
Όταν εκτελείτε τον παραπάνω κώδικα, λαμβάνετε την ακόλουθη έξοδο:
Παραγωγή:
Τα ονόματα των νημάτων εξάγονται εδώ ως
- Γκουρού
- Γκουρού2
Παράδειγμα 2:
Σε αυτό το παράδειγμα, θα μάθουμε για τις μεθόδους παράκαμψης run () και start () μιας διεπαφής με δυνατότητα εκτέλεσης και θα δημιουργήσουμε δύο νήματα αυτής της κλάσης και θα τα τρέξουμε ανάλογα.
Επίσης, παίρνουμε δύο μαθήματα,
- Ένα που θα εφαρμόσει τη διεπαφή με δυνατότητα εκτέλεσης και
- Ένα άλλο που θα έχει την κύρια μέθοδο και θα εκτελεί ανάλογα.
demotest πακέτουδημόσια τάξη GuruThread2 {Δημόσιο στατικό κενό (String [] args) {// TODO Αυτόματο δημιουργημένο στέλεχος μεθόδουGuruThread3 threadguru1 = νέο GuruThread3 ("guru1");threadguru1.start ();GuruThread3 threadguru2 = νέο GuruThread3 ("guru2");threadguru2.start ();}}class GuruThread3 υλοποιεί το Runnable {Νήμα guruthread;ιδιωτική συμβολοσειρά guruname;GuruThread3 (Όνομα συμβολοσειράς) {guruname = όνομα;}@Καταπατώδημόσια άκυρη εκτέλεση () {System.out.println ("Thread running" + guruname);για (int i = 0; i <4; i ++) {System.out.println (i);System.out.println (guruname);προσπαθήστε {Thread.sleep (1000);} αλίευση (InterruptException e) {System.out.println ("Το νήμα έχει διακοπεί");}}}δημόσια άκυρη εκκίνηση () {System.out.println ("Το νήμα ξεκίνησε");αν (guruthread == null) {guruthread = νέο νήμα (αυτό, guruname);guruthread.start ();}}}
Επεξήγηση του κωδικού:
- Γραμμή κώδικα 2: Εδώ παίρνουμε μια τάξη "GuruThread2" που θα έχει την κύρια μέθοδο σε αυτό.
- Γραμμή κώδικα 4: Εδώ παίρνουμε μια κύρια μέθοδο της τάξης.
- Γραμμή κώδικα 6-7: Εδώ δημιουργούμε μια παρουσία της κλάσης GuruThread3 (η οποία δημιουργείται στις παρακάτω γραμμές του κώδικα) ως "threadguru1" και ξεκινάμε το νήμα.
- Γραμμή κώδικα 8-9: Εδώ δημιουργούμε μια άλλη παρουσία της κλάσης GuruThread3 (η οποία δημιουργείται στις παρακάτω γραμμές του κώδικα) ως "threadguru2" και ξεκινάμε το νήμα.
- Γραμμή κώδικα 11: Εδώ δημιουργούμε μια τάξη "GuruThread3" που εφαρμόζει τη διεπαφή με δυνατότητα εκτέλεσης (θα πρέπει να εφαρμοστεί από οποιαδήποτε κλάση των οποίων οι παρουσίες προορίζονται να εκτελεστούν από το νήμα.)
- Γραμμή κώδικα 13-14: παίρνουμε δύο μεταβλητές κατηγορίας από τις οποίες η μία είναι η κλάση νημάτων τύπου και άλλη από την κλάση συμβολοσειρών.
- Γραμμή κώδικα 15-18: παρακάμπτουμε τον κατασκευαστή GuruThread3, ο οποίος παίρνει ένα όρισμα ως τύπος συμβολοσειράς (που είναι όνομα νημάτων) που αντιστοιχεί στη μεταβλητή κλάσης guruname και επομένως αποθηκεύεται το όνομα του νήματος.
- Γραμμή κώδικα 20: Εδώ παρακάμπτουμε τη μέθοδο run () της διεπαφής με δυνατότητα εκτέλεσης.
- Γραμμή κώδικα 21: Έχουμε βγάλει το όνομα του νήματος χρησιμοποιώντας τη δήλωση println.
- Γραμμή κώδικα 22-31: Εδώ χρησιμοποιούμε ένα βρόχο για το με μετρητή αρχικοποιημένο στο 0, και δεν θα πρέπει να είναι μικρότερο από 4 (μπορούμε να πάρουμε οποιοδήποτε αριθμό, επομένως εδώ ο βρόχος θα τρέξει 4 φορές) και αυξάνοντας τον μετρητή. Εκτυπώνουμε το όνομα του νήματος και καθιστούμε επίσης το νήμα σε αναστολή λειτουργίας για 1000 χιλιοστά του δευτερολέπτου μέσα σε ένα μπλοκ δοκιμής, καθώς η μέθοδος ύπνου αύξησε την ελεγχόμενη εξαίρεση.
- Γραμμή κώδικα 33: Εδώ παρακάμπτουμε τη μέθοδο εκκίνησης της διεπαφής με δυνατότητα εκτέλεσης.
- Γραμμή κώδικα 35: Έχουμε βγάλει το κείμενο "Το νήμα ξεκίνησε"
- Γραμμή κώδικα 36-40: Εδώ παίρνουμε μια συνθήκη if για να ελέγξουμε αν η μεταβλητή κλάσης guruthread έχει αξία σε αυτήν ή όχι. Εάν είναι μηδέν, τότε δημιουργούμε μια παρουσία χρησιμοποιώντας κλάση νήματος που παίρνει το όνομα ως παράμετρος (τιμή για την οποία εκχωρήθηκε στον κατασκευαστή). Μετά το οποίο ξεκινά το νήμα χρησιμοποιώντας τη μέθοδο start ().
Όταν εκτελείτε τον παραπάνω κώδικα λαμβάνετε την ακόλουθη έξοδο:
Έξοδος :
Υπάρχουν δύο νήματα ως εκ τούτου, παίρνουμε δύο φορές το μήνυμα "Το νήμα ξεκίνησε".
Παίρνουμε τα ονόματα του νήματος καθώς τα έχουμε βγάλει.
Πηγαίνει για βρόχο όπου εκτυπώνουμε το μετρητή και το όνομα του νήματος και ο μετρητής ξεκινά με 0.
Ο βρόχος εκτελείται τρεις φορές και στο μεταξύ του νήματος κοιμάται για 1000 χιλιοστά του δευτερολέπτου.
Ως εκ τούτου, πρώτα, παίρνουμε τον γκουρού 1 και τον γκουρού 2 και πάλι τον γκουρού2 επειδή το νήμα κοιμάται εδώ για 1000 χιλιοστά του δευτερολέπτου και στη συνέχεια τον επόμενο γκουρού 1 και πάλι τον γκουρού 1, το νήμα κοιμάται για 1000 χιλιοστά του δευτερολέπτου, οπότε παίρνουμε τον γκουρού 2 και μετά τον γκουρού 1.
Περίληψη :
Σε αυτό το σεμινάριο, είδαμε εφαρμογές πολλαπλών νημάτων στην Java και πώς να χρησιμοποιούμε μεμονωμένα και πολλαπλά θέματα.
- Στο multithreading, οι χρήστες δεν αποκλείονται καθώς τα νήματα είναι ανεξάρτητα και μπορούν να εκτελούν πολλές λειτουργίες ταυτόχρονα
- Διάφορα στάδια του κύκλου ζωής του νήματος είναι,
- Νέος
- Τρέξιμο
- Τρέξιμο
- Αναμονή
- Νεκρός
- Μάθαμε επίσης για το συγχρονισμό μεταξύ νημάτων, τα οποία βοηθούν την εφαρμογή να λειτουργεί ομαλά.
- Το multithreading διευκολύνει πολύ περισσότερες εργασίες.