Νήμα αναφέρεται στην πρακτική της εκτέλεσης διαδικασιών προγραμματισμού ταυτόχρονα για τη βελτίωση της απόδοσης της εφαρμογής. Αν και δεν είναι τόσο συνηθισμένο να δουλεύετε με νήματα απευθείας σε επιχειρηματικές εφαρμογές, χρησιμοποιούνται συνεχώς σε πλαίσια Java.
Για παράδειγμα, τα πλαίσια που επεξεργάζονται μεγάλο όγκο πληροφοριών, όπως το Spring Batch, χρησιμοποιούν νήματα για τη διαχείριση δεδομένων. Ο χειρισμός νημάτων ή διεργασιών CPU βελτιώνει ταυτόχρονα την απόδοση, με αποτέλεσμα ταχύτερα, πιο αποτελεσματικά προγράμματα.
Λάβετε τον πηγαίο κώδικα
Λάβετε τον κωδικό για αυτό το Java Challenger. Μπορείτε να εκτελέσετε τις δικές σας δοκιμές ενώ ακολουθείτε τα παραδείγματα.
Βρείτε το πρώτο σας νήμα: Κύρια μέθοδος () της Java
Ακόμα κι αν δεν έχετε δουλέψει ποτέ άμεσα με νήματα Java, έχετε εργαστεί έμμεσα μαζί τους επειδή η κύρια μέθοδος Java περιέχει ένα κύριο νήμα. Οποτεδήποτε έχετε εκτελέσει το κύριος()
μέθοδος, έχετε επίσης εκτελέσει το κύριο Νήμα
.
Μελετώντας το Νήμα
Το μάθημα είναι πολύ χρήσιμο για την κατανόηση του τρόπου λειτουργίας του νήματος σε προγράμματα Java. Μπορούμε να αποκτήσουμε πρόσβαση στο νήμα που εκτελείται επικαλούμενος το currentThread (). getName ()
μέθοδο, όπως φαίνεται εδώ:
δημόσια τάξη MainThread {public static void main (String ... mainThread) {System.out.println (Thread.currentThread (). getName ()); }}
Αυτός ο κωδικός θα εκτυπώσει "main", προσδιορίζοντας το νήμα που εκτελείται αυτήν τη στιγμή. Η γνώση του τρόπου αναγνώρισης του νήματος που εκτελείται είναι το πρώτο βήμα για την απορρόφηση των εννοιών του νήματος.
Ο κύκλος ζωής του νήματος Java
Όταν εργάζεστε με νήματα, είναι σημαντικό να γνωρίζετε την κατάσταση του νήματος. Ο κύκλος ζωής νήματος Java αποτελείται από έξι καταστάσεις νημάτων:
- Νέος: Ενα νέο
Νήμα()
έχει δημιουργηθεί. - Τρέξιμο: Ο
Νήμα
'μικρόαρχή()
έχει χρησιμοποιηθεί η μέθοδος. - Τρέξιμο: Ο
αρχή()
έχει χρησιμοποιηθεί η μέθοδος και το νήμα εκτελείται. - Ανασταλεί: Το νήμα έχει τεθεί προσωρινά σε αναστολή και μπορεί να συνεχιστεί από άλλο νήμα.
- Αποκλείστηκε: Το νήμα περιμένει μια ευκαιρία να τρέξει. Αυτό συμβαίνει όταν ένα νήμα έχει ήδη επικαλεστεί το
συγχρονισμένος ()
μέθοδος και το επόμενο νήμα πρέπει να περιμένει μέχρι να τελειώσει. - Τερματίστηκε: Η εκτέλεση του νήματος έχει ολοκληρωθεί.

Υπάρχουν περισσότερα για να εξερευνήσετε και να κατανοήσετε τις καταστάσεις νήματος, αλλά οι πληροφορίες στο Σχήμα 1 είναι αρκετές για να λύσετε αυτήν την πρόκληση Java.
Ταυτόχρονη επεξεργασία: Επέκταση κλάσης νήματος
Στην απλούστερη, ταυτόχρονη επεξεργασία γίνεται με επέκταση a Νήμα
τάξη, όπως φαίνεται παρακάτω.
δημόσια κλάση Το InheritingThread επεκτείνει το νήμα {InheritingThread (String threadName) {super (threadName); } δημόσιος στατικός κενός κενός (String ... κληρονομικό) {System.out.println (Thread.currentThread (). getName () + "is running"); νέο InheritingThread ("inheritingThread"). έναρξη (); } @Override public void run () {System.out.println (Thread.currentThread (). GetName () + "is running"); }}
Εδώ τρέχουμε δύο νήματα: το Κύριο νήμα
και το Κληρονομικό νήμα
. Όταν επικαλούμεθα το αρχή()
μέθοδο με το νέο κληρονομιάThread ()
, η λογική στο τρέξιμο()
η μέθοδος εκτελείται.
Περνάμε επίσης το όνομα του δεύτερου νήματος στο Νήμα
κατασκευαστής κλάσης, οπότε η έξοδος θα είναι:
το main τρέχει. Το κληρονομικόThread εκτελείται.
Η διεπαφή με δυνατότητα εκτέλεσης
Αντί να χρησιμοποιήσετε κληρονομιά, θα μπορούσατε να εφαρμόσετε τη διεπαφή Runnable. Πέρασμα Τρέξιμο
μέσα σε ένα Νήμα
Ο κατασκευαστής έχει ως αποτέλεσμα λιγότερη σύζευξη και μεγαλύτερη ευελιξία. Αφού περάσει Τρέξιμο
, μπορούμε να επικαλεστούμε το αρχή()
μέθοδο όπως ακριβώς κάναμε στο προηγούμενο παράδειγμα:
δημόσια κλάση RunnableThread υλοποιεί Runnable {public static void main (String ... runnableThread) {System.out.println (Thread.currentThread (). getName ()); νέο νήμα (νέο RunnableThread ()). έναρξη (); } @Override public void run () {System.out.println (Thread.currentThread (). GetName ()); }}
Νήματα χωρίς δαίμονα έναντι δαίμονα
Όσον αφορά την εκτέλεση, υπάρχουν δύο τύποι νημάτων:
- Νήματα χωρίς δαίμονα εκτελούνται μέχρι το τέλος. Το κύριο νήμα είναι ένα καλό παράδειγμα ενός νήματος χωρίς δαίμονα. Κωδικός σε
κύριος()
θα εκτελείται πάντα μέχρι το τέλος, εκτός ανSystem.exit ()
αναγκάζει το πρόγραμμα να ολοκληρωθεί. - ΕΝΑ νήμα δαίμονα είναι το αντίθετο, βασικά μια διαδικασία που δεν απαιτείται να εκτελεστεί μέχρι το τέλος.
Θυμηθείτε τον κανόνα: Εάν ένα νήμα χωρίς δαίμονα περικλείει πριν από ένα νήμα δαίμονα, το νήμα δαίμονα δεν θα εκτελεστεί μέχρι το τέλος.
Για να κατανοήσετε καλύτερα τη σχέση των νήσων δαίμονα και μη δαίμονα, μελετήστε αυτό το παράδειγμα:
εισαγωγή java.util.stream.IntStream; δημόσια κλάση NonDaemonAndDaemonThread {public static void main (String ... nonDaemonAndDaemon) ρίχνει το InterruptException {System.out.println ("Έναρξη εκτέλεσης στο νήμα" + Thread.currentThread (). getName ()); Thread daemonThread = νέο νήμα (() -> IntStream.rangeClosed (1, 100000) .forEach (System.out :: println)); daemonThread.setDaemon (true); daemonThread.start (); Thread.sleep (10); System.out.println ("Τέλος εκτέλεσης στο νήμα" + Thread.currentThread (). GetName ()); }}
Σε αυτό το παράδειγμα έχω χρησιμοποιήσει ένα νήμα δαίμονα για να δηλώσω ένα εύρος από 1 έως 100.000, να επαναλάβω όλα αυτά και μετά να εκτυπώσω. Αλλά θυμηθείτε, ένα νήμα δαίμονα δεν θα ολοκληρώσει την εκτέλεση εάν το κύριο νήμα του μη-δαιμόνων τελειώσει πρώτα.
Η έξοδος θα προχωρήσει ως εξής:
- Έναρξη εκτέλεσης στο κύριο νήμα.
- Εκτυπώστε αριθμούς από 1 έως πιθανώς 100.000.
- Τέλος εκτέλεσης στο κύριο νήμα, πολύ πιθανό πριν ολοκληρωθεί η επανάληψη έως 100.000.
Το τελικό αποτέλεσμα θα εξαρτηθεί από την εφαρμογή JVM.
Και αυτό με φέρνει στο επόμενο σημείο: τα νήματα είναι απρόβλεπτα.
Προτεραιότητα σπειρώματος και JVM
Είναι δυνατό να δοθεί προτεραιότητα στην εκτέλεση του νήματος με το setPriority
μέθοδος, αλλά ο τρόπος αντιμετώπισής της εξαρτάται από την εφαρμογή JVM. Όλα τα Linux, MacOS και Windows έχουν διαφορετικές υλοποιήσεις JVM και το καθένα θα χειρίζεται την προτεραιότητα του νήματος σύμφωνα με τις δικές του προεπιλογές.
Η προτεραιότητα νήματος που ορίζετε επηρεάζει τη σειρά της επίκλησης νήματος, ωστόσο. Οι τρεις σταθερές δηλώθηκαν στο Νήμα
η τάξη είναι:
/ ** * Η ελάχιστη προτεραιότητα που μπορεί να έχει ένα νήμα. * / δημόσιο στατικό τελικό int MIN_PRIORITY = 1; / ** * Η προεπιλεγμένη προτεραιότητα που έχει εκχωρηθεί σε ένα νήμα. * / δημόσιο στατικό τελικό int NORM_PRIORITY = 5; / ** * Η μέγιστη προτεραιότητα που μπορεί να έχει ένα νήμα. * / public static final int MAX_PRIORITY = 10;
Δοκιμάστε να εκτελέσετε ορισμένες δοκιμές στον ακόλουθο κώδικα για να δείτε με ποια προτεραιότητα εκτέλεσης καταλήγετε:
δημόσια τάξη ThreadPriority {public static void main (String ... threadPriority) {Thread moeThread = new Thread (() -> System.out.println ("Moe")); Thread barneyThread = νέο Thread (() -> System.out.println ("Barney")); Thread homerThread = νέο νήμα (() -> System.out.println ("Homer")); moeThread.setPriority (Thread.MAX_PRIORITY); barneyThread.setPriority (Thread.NORM_PRIORITY); homerThread.setPriority (Νήμα.MIN_PRIORITY); homerThread.start (); barneyThread.start (); moeThread.start (); }}
Ακόμα κι αν βάλουμε moe νήμα
όπως και MAX_PRIORITY
, δεν μπορούμε να βασιστούμε σε αυτό το νήμα που θα εκτελεστεί πρώτα. Αντ 'αυτού, η σειρά εκτέλεσης θα είναι τυχαία.
Σταθερές έναντι αριθμών
ο Νήμα
Η τάξη παρουσιάστηκε με το Java 1.0. Εκείνη την εποχή, οι προτεραιότητες καθορίστηκαν χρησιμοποιώντας σταθερές, όχι αριθμούς. Υπάρχει πρόβλημα με τη χρήση σταθερών, ωστόσο: εάν περάσουμε έναν αριθμό προτεραιότητας που δεν κυμαίνεται από 1 έως 10, το setPriority ()
μέθοδος θα ρίξει ένα IllegalArgumentException. Σήμερα, μπορούμε να χρησιμοποιήσουμε αριθμούς για να αντιμετωπίσουμε αυτό το ζήτημα. Η χρήση του enums καθιστά αδύνατο να περάσει ένα παράνομο επιχείρημα, το οποίο και οι δύο απλοποιεί τον κώδικα και μας δίνει μεγαλύτερο έλεγχο στην εκτέλεση του.
Πάρτε την πρόκληση για τα θέματα Java!
Έχετε μάθει λίγα πράγματα για τα θέματα, αλλά αρκεί για την πρόκληση Java αυτής της ανάρτησης.
Για να ξεκινήσετε, μελετήστε τον ακόλουθο κώδικα:
δημόσια τάξη ThreadChallenge {private static int wolverineAdrenaline = 10; public static void main (String ... doYourBest) {new Motorcycle ("Harley Davidson"). έναρξη (); Μοτοσικλέτα fastBike = νέα μοτοσικλέτα ("Dodge Tomahawk"); fastBike.setPriority (Νήμα.MAX_PRIORITY); fastBike.setDaemon (false); fastBike.start (); Μοτοσικλέτα yamaha = νέα μοτοσικλέτα ("Yamaha YZF"); yamaha.setPriority (Νήμα.MIN_PRIORITY); yamaha.start (); } Στατική τάξη Η μοτοσικλέτα επεκτείνει το νήμα {Motorcycle (String bikeName) {super (bikeName); } @Override public void run () {wolverineAdrenaline ++; if (wolverineAdrenaline == 13) {System.out.println (this.getName ()); }}}}
Ποια θα είναι η έξοδος αυτού του κώδικα; Αναλύστε τον κώδικα και προσπαθήστε να προσδιορίσετε την απάντηση για εσάς, με βάση αυτά που έχετε μάθει.
Α. Harley Davidson
Β. Dodge Tomahawk
Γ. Yamaha YZF
Δ. Αόριστη
Τι συνέβη μόλις τώρα? Κατανόηση της συμπεριφοράς των νημάτων
Στον παραπάνω κώδικα, δημιουργήσαμε τρία νήματα. Το πρώτο νήμα είναι Χάρλεϊ Ντέιβιντσον
και εκχωρήσαμε σε αυτό το νήμα την προεπιλεγμένη προτεραιότητα. Το δεύτερο νήμα είναι Dodge Tomahawk
, ανατεθεί MAX_PRIORITY
. Το τρίτο είναι Yamaha YZF
, με MIN_PRIORITY
. Στη συνέχεια ξεκινήσαμε τα νήματα.
Για να προσδιορίσετε τη σειρά με την οποία θα εκτελούνται τα νήματα, ίσως πρώτα να σημειώσετε ότι το Μοτοσυκλέτα
η τάξη επεκτείνει το Νήμα
τάξη και ότι έχουμε περάσει το όνομα του νήματος στον κατασκευαστή. Έχουμε επίσης παρακάμψει το τρέξιμο()
μέθοδος με συνθήκη: εάν η αδρεναλίνη wolverine ισούται με 13
.
Αν και Yamaha YZF
είναι το τρίτο νήμα στη σειρά εκτέλεσης και έχει MIN_PRIORITY
, δεν υπάρχει καμία εγγύηση ότι θα εκτελεστεί τελευταία για όλες τις υλοποιήσεις JVM.
Μπορείτε επίσης να σημειώσετε ότι σε αυτό το παράδειγμα ορίζουμε το Dodge Tomahawk
νήμα ως δαίμονας
. Επειδή είναι νήμα δαίμονα, Dodge Tomahawk
μπορεί ποτέ να ολοκληρωθεί η εκτέλεση. Αλλά τα άλλα δύο νήματα είναι μη δαίμονας από προεπιλογή, έτσι το Χάρλεϊ Ντέιβιντσον
και Yamaha YZF
Τα νήματα θα ολοκληρώσουν σίγουρα την εκτέλεσή τους.
Εν κατακλείδι, το αποτέλεσμα θα είναι Δ: Αόριστη, επειδή δεν υπάρχει καμία εγγύηση ότι ο προγραμματιστής νημάτων θα ακολουθήσει τη σειρά εκτέλεσης ή την προτεραιότητα του νήματος.
Θυμηθείτε, δεν μπορούμε να βασιστούμε στη λογική του προγράμματος (σειρά νήματος ή προτεραιότητα νήματος) για να προβλέψουμε τη σειρά εκτέλεσης του JVM.
Πρόκληση βίντεο! Εντοπισμός μεταβλητών ορισμάτων
Ο εντοπισμός σφαλμάτων είναι ένας από τους ευκολότερους τρόπους για να απορροφήσετε πλήρως τις έννοιες προγραμματισμού, βελτιώνοντας παράλληλα τον κώδικά σας. Σε αυτό το βίντεο μπορείτε να ακολουθήσετε ενώ εντοπίζω το σφάλμα και εξηγώ την πρόκληση συμπεριφοράς νήματος:
Συνηθισμένα λάθη με νήματα Java
- Επίκληση του
τρέξιμο()
μέθοδος για να προσπαθήσετε να ξεκινήσετε ένα νέο νήμα. - Προσπαθώντας να ξεκινήσετε ένα νήμα δύο φορές (αυτό θα προκαλέσει ένα
IllegalThreadStateException
). - Επιτρέποντας σε πολλές διαδικασίες να αλλάξουν την κατάσταση ενός αντικειμένου, όταν δεν πρέπει να αλλάξουν.
- Σύνταξη λογικής προγράμματος που βασίζεται στην προτεραιότητα του νήματος (δεν μπορείτε να το προβλέψετε).
- Βασισμένο στη σειρά εκτέλεσης του νήματος - ακόμη και αν ξεκινήσουμε πρώτα ένα νήμα, δεν υπάρχει καμία εγγύηση ότι θα εκτελεστεί πρώτα.
Τι να θυμάστε για τα νήματα Java
- Επικαλέστε το
αρχή()
μέθοδος εκκίνησης αΝήμα
. - Είναι δυνατό να επεκταθεί το
Νήμα
τάξη απευθείας για να χρησιμοποιήσετε νήματα. - Είναι δυνατόν να εφαρμοστεί μια ενέργεια νήματος μέσα σε ένα
Τρέξιμο
διεπαφή. - Η προτεραιότητα του νήματος εξαρτάται από την εφαρμογή JVM.
- Η συμπεριφορά του νήματος θα εξαρτάται πάντα από την εφαρμογή JVM.
- Ένα νήμα δαίμονα δεν θα ολοκληρωθεί εάν ένα νήμα που δεν περιλαμβάνει δαίμονα τελειώνει πρώτα.
Μάθετε περισσότερα για τα νήματα Java στο JavaWorld
- Διαβάστε τη σειρά νημάτων Java 101 για να μάθετε περισσότερα σχετικά με τα νήματα και τα runnables, τον συγχρονισμό νημάτων, τον προγραμματισμό νημάτων με αναμονή / ειδοποίηση και το θάνατο νήματος.
- Μοντέρνο νήμα: Εισάγει ένα αστάρι ταυτόχρονης Java
java.util.concurrent
και απαντά σε κοινές ερωτήσεις για προγραμματιστές νέους στην ταυτόχρονη Java. - Το μοντέρνο νήμα για μη αρχάριους προσφέρει πιο προηγμένες συμβουλές και βέλτιστες πρακτικές για εργασία
java.util.concurrent
.
Περισσότερα από τον Rafael
- Λάβετε περισσότερες γρήγορες συμβουλές κώδικα: Διαβάστε όλες τις δημοσιεύσεις στη σειρά Java Challengers.
- Δημιουργήστε τις ικανότητές σας Java: Επισκεφθείτε το Java Dev Gym για προπόνηση κώδικα.
- Θέλετε να εργαστείτε σε έργα χωρίς άγχος και να γράψετε κώδικα χωρίς σφάλματα; Επισκεφτείτε το NoBugsProject για το αντίγραφο του Χωρίς σφάλματα, χωρίς άγχος - Δημιουργήστε ένα λογισμικό που αλλάζει τη ζωή χωρίς να καταστρέψει τη ζωή σας.
Αυτή η ιστορία, "Η συμπεριφορά του νήματος στο JVM" δημοσιεύτηκε αρχικά από την JavaWorld.