Προγραμματισμός

Πώς εκτελεί η εικονική μηχανή Java συγχρονισμό νήματος

Όλα τα προγράμματα Java συγκεντρώνονται σε αρχεία κλάσης, τα οποία περιέχουν bytecodes, τη γλώσσα μηχανής της εικονικής μηχανής Java. Αυτό το άρθρο ρίχνει μια ματιά στον τρόπο χειρισμού του συγχρονισμού νήματος από την εικονική μηχανή Java, συμπεριλαμβανομένων των σχετικών κωδικών bytecodes. (1.750 λέξεις)

Αυτό το μήνα Κάτω από την κουκούλα εξετάζει το συγχρονισμό νήματος τόσο στη γλώσσα Java όσο και στην εικονική μηχανή Java (JVM). Αυτό το άρθρο είναι το τελευταίο στη μεγάλη σειρά άρθρων bytecode που ξεκίνησα το περασμένο καλοκαίρι. Περιγράφει τους μόνο δύο opcodes που σχετίζονται άμεσα με το συγχρονισμό νήματος, τους opcodes που χρησιμοποιούνται για είσοδο και έξοδο από οθόνες.

Θέματα και κοινόχρηστα δεδομένα

Ένα από τα πλεονεκτήματα της γλώσσας προγραμματισμού Java είναι η υποστήριξή του για πολλαπλές κλωστές σε επίπεδο γλώσσας. Μεγάλο μέρος αυτής της υποστήριξης επικεντρώνεται στον συντονισμό της πρόσβασης σε δεδομένα που μοιράζονται μεταξύ πολλών νημάτων.

Το JVM οργανώνει τα δεδομένα μιας τρέχουσας εφαρμογής Java σε διάφορες περιοχές δεδομένων χρόνου εκτέλεσης: μία ή περισσότερες στοίβες Java, έναν σωρό και μια περιοχή μεθόδων. Για ένα υπόβαθρο σε αυτές τις περιοχές μνήμης, δείτε το πρώτο Κάτω από την κουκούλα άρθρο: "Η αδύνατη, μέση εικονική μηχανή."

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

Υπάρχει μόνο ένα σωρός μέσα στο JVM και όλα τα νήματα το μοιράζονται. Ο σωρός δεν περιέχει παρά αντικείμενα. Δεν υπάρχει τρόπος να τοποθετήσετε έναν μοναδικό πρωτόγονο τύπο ή αναφορά αντικειμένου στο σωρό - αυτά τα πράγματα πρέπει να αποτελούν μέρος ενός αντικειμένου. Οι συστοιχίες βρίσκονται στο σωρό, συμπεριλαμβανομένων συστοιχιών πρωτόγονων τύπων, αλλά στην Ιάβα, οι συστοιχίες είναι επίσης αντικείμενα.

Εκτός από τη στοίβα Java και το σωρό, τα άλλα δεδομένα θέσης που μπορούν να βρίσκονται στο JVM είναι το περιοχή μεθόδου, που περιέχει όλες τις μεταβλητές τάξης (ή στατικές) που χρησιμοποιούνται από το πρόγραμμα. Η περιοχή μεθόδου είναι παρόμοια με τη στοίβα, καθώς περιέχει μόνο πρωτόγονους τύπους και αναφορές αντικειμένων. Σε αντίθεση με τη στοίβα, ωστόσο, οι μεταβλητές κλάσης στην περιοχή μεθόδου κοινοποιούνται από όλα τα νήματα.

Κλειδαριές αντικειμένου και τάξης

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

  • Ο σωρός, ο οποίος περιέχει όλα τα αντικείμενα
  • Η περιοχή μεθόδου, η οποία περιέχει όλες τις μεταβλητές τάξης

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

Για να συντονιστεί η πρόσβαση σε κοινόχρηστα δεδομένα μεταξύ πολλών νημάτων, η εικονική μηχανή Java συσχετίζει ένα κλειδαριά με κάθε αντικείμενο και κατηγορία. Η κλειδαριά είναι σαν προνόμιο που μόνο ένα νήμα μπορεί να "κατέχει" κάθε φορά. Εάν ένα νήμα θέλει να κλειδώσει ένα συγκεκριμένο αντικείμενο ή κλάση, ρωτά την JVM. Σε κάποιο σημείο αφού το νήμα ζητήσει από την JVM κλειδαριά - ίσως πολύ σύντομα, ίσως αργότερα, πιθανώς ποτέ - η JVM δίνει το κλείδωμα στο νήμα. Όταν το νήμα δεν χρειάζεται πλέον το κλείδωμα, το επιστρέφει στο JVM. Εάν κάποιο άλλο νήμα έχει ζητήσει το ίδιο κλείδωμα, το JVM περνά την κλειδαριά σε αυτό το νήμα.

Οι κλειδαριές κλάσης εφαρμόζονται στην πραγματικότητα ως κλειδαριές αντικειμένων. Όταν το JVM φορτώνει ένα αρχείο κλάσης, δημιουργεί μια παρουσία κλάσης java.lang.Class. Όταν κλειδώνετε μια τάξη, κλειδώνετε πραγματικά αυτήν την τάξη Τάξη αντικείμενο.

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

Οθόνες

Το JVM χρησιμοποιεί κλειδαριές σε συνδυασμό με οθόνες. Ένα μόνιτορ είναι βασικά ένας φύλακας στο ότι παρακολουθεί μια ακολουθία κώδικα, διασφαλίζοντας ότι μόνο ένα νήμα τη φορά εκτελεί τον κώδικα.

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

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

Πολλαπλές κλειδαριές

Επιτρέπεται σε ένα νήμα να κλειδώνει το ίδιο αντικείμενο πολλές φορές. Για κάθε αντικείμενο, το JVM διατηρεί ένα πλήθος των φορών που το αντικείμενο έχει κλειδωθεί. Ένα ξεκλειδωμένο αντικείμενο έχει αριθμό μηδέν. Όταν ένα νήμα αποκτά το κλείδωμα για πρώτη φορά, ο αριθμός αυξάνεται σε ένα. Κάθε φορά που το νήμα αποκτά μια κλειδαριά στο ίδιο αντικείμενο, αυξάνεται ένας αριθμός. Κάθε φορά που το νήμα απελευθερώνει την κλειδαριά, η μέτρηση μειώνεται. Όταν το πλήθος φτάσει στο μηδέν, το κλείδωμα απελευθερώνεται και διατίθεται σε άλλα νήματα.

Συγχρονισμένα μπλοκ

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

Συγχρονισμένες δηλώσεις

Για να δημιουργήσετε μια συγχρονισμένη δήλωση, χρησιμοποιείτε το συγχρονισμένος λέξη-κλειδί με μια έκφραση που αξιολογείται σε μια αναφορά αντικειμένου, όπως στο αντίστροφη σειρά() παρακάτω μέθοδος:

τάξη KitchenSync {private int [] intArray = new int [10]; void reverseOrder () {συγχρονισμένο (αυτό) {int halfWay = intArray.length / 2; για (int i = 0; i <halfWay; ++ i) {int upperIndex = intArray.length - 1 - i; int save = intArray [άνωIndex]; intArray [upperIndex] = intArray [i]; intArray [i] = αποθήκευση; }}}}

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

Δύο opcodes, παρατηρητής και monitorexit, χρησιμοποιούνται για μπλοκ συγχρονισμού εντός μεθόδων, όπως φαίνεται στον παρακάτω πίνακα.

Πίνακας 1. Οθόνες

Κώδικας πράξηςOperand (ες)Περιγραφή
παρατηρητήςκανέναςpop αντικείμενοref, αποκτήστε το κλείδωμα που σχετίζεται με το αντικείμενο
monitorexitκανέναςανοίξτε το αντικείμενο, απελευθερώστε το κλείδωμα που σχετίζεται με το αντικείμενο

Πότε παρατηρητής συναντάται από την εικονική μηχανή Java, αποκτά την κλειδαριά για το αντικείμενο που αναφέρεται από το αντικείμενοref στη στοίβα. Εάν το νήμα κατέχει ήδη το κλείδωμα για αυτό το αντικείμενο, αυξάνεται ένα πλήθος. Κάθε φορά monitorexit εκτελείται για το νήμα στο αντικείμενο, η μέτρηση μειώνεται. Όταν η μέτρηση φτάσει στο μηδέν, η οθόνη απελευθερώνεται.

Ρίξτε μια ματιά στην ακολουθία bytecode που δημιουργείται από το αντίστροφη σειρά() μέθοδος του KitchenSync τάξη.

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

Συγχρονισμένες μέθοδοι

Για να συγχρονίσετε μια ολόκληρη μέθοδο, απλώς συμπεριλάβετε το συγχρονισμένος λέξη-κλειδί ως ένας από τους προσδιοριστές μεθόδου, όπως σε:

κλάση HeatSync {private int [] intArray = new int [10]; συγχρονισμένο void reverseOrder () {int halfWay = intArray.length / 2; για (int i = 0; i <halfWay; ++ i) {int upperIndex = intArray.length - 1 - i; int save = intArray [άνωIndex]; intArray [upperIndex] = intArray [i]; intArray [i] = αποθήκευση; }}}

Το JVM δεν χρησιμοποιεί ειδικά opcodes για να επικαλεσθεί ή να επιστρέψει από συγχρονισμένες μεθόδους. Όταν το JVM επιλύει τη συμβολική αναφορά σε μια μέθοδο, καθορίζει εάν η μέθοδος είναι συγχρονισμένη. Εάν είναι, η JVM αποκτά ένα κλείδωμα πριν επικαλεστεί τη μέθοδο. Για μια μέθοδο παρουσίας, η JVM αποκτά το κλείδωμα που σχετίζεται με το αντικείμενο στο οποίο γίνεται επίκληση της μεθόδου. Για μια μέθοδο κλάσης, αποκτά το κλείδωμα που σχετίζεται με την κλάση στην οποία ανήκει η μέθοδος. Αφού ολοκληρωθεί μια συγχρονισμένη μέθοδος, είτε ολοκληρώνεται επιστρέφοντας είτε ρίχνοντας μια εξαίρεση, το κλείδωμα απελευθερώνεται.

Ερχόμενος τον επόμενο μήνα

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

Ο Bill Venners γράφει λογισμικό επαγγελματικά για 12 χρόνια. Με έδρα τη Silicon Valley, παρέχει υπηρεσίες παροχής συμβουλών και εκπαίδευσης λογισμικού με το όνομα Artima Software Company. Με τα χρόνια έχει αναπτύξει λογισμικό για τις βιομηχανίες ηλεκτρονικών ειδών ευρείας κατανάλωσης, εκπαίδευσης, ημιαγωγών και ασφάλισης ζωής. Έχει προγραμματίσει σε πολλές γλώσσες σε πολλές πλατφόρμες: γλώσσα συναρμολόγησης σε διάφορους μικροεπεξεργαστές, C στο Unix, C ++ σε Windows, Java στον Ιστό. Είναι συγγραφέας του βιβλίου: Inside the Java Virtual Machine, που εκδόθηκε από τον McGraw-Hill.

Μάθετε περισσότερα σχετικά με αυτό το θέμα

  • Το βιβλίο Η προδιαγραφή εικονικής μηχανής Java (//www.aw.com/cp/lindholm-yellin.html), των Tim Lindholm και Frank Yellin (ISBN 0-201-63452-X), μέρος της σειράς Java (//www.aw.com/cp /javaseries.html), από το Addison-Wesley, είναι η οριστική αναφορά εικονικής μηχανής Java.
  • Προηγούμενα άρθρα "Under The Hood":
  • "Το Lean, Mean Virtual Machine" Εισάγει την εικονική μηχανή Java.
  • "Ο τρόπος ζωής αρχείων κατηγορίας Java" Δίνει μια επισκόπηση στο αρχείο κλάσης Java, τη μορφή αρχείου στην οποία συντάσσονται όλα τα προγράμματα Java.
  • Το "Java's Garbage-Collected Heap" δίνει μια επισκόπηση της συλλογής απορριμμάτων γενικά και του σωρού που συλλέγεται σκουπίδια της εικονικής μηχανής Java ειδικότερα.
  • "Βασικά Bytecode" Παρουσιάζει τους bytecodes της εικονικής μηχανής Java και συζητά συγκεκριμένους τύπους, λειτουργίες μετατροπής και λειτουργίες στοίβας.
  • "Floating Point Arithmetic" Περιγράφει την υποστήριξη κινούμενου σημείου της εικονικής μηχανής Java και τους κωδικούς bytec που εκτελούν λειτουργίες κινούμενου σημείου.
  • "Λογική και αριθμητική" Περιγράφει την υποστήριξη της εικονικής μηχανής Java για λογική και ακέραια αριθμητική και τους σχετικούς bytecodes.
  • "Αντικείμενα και πίνακες" Περιγράφει τον τρόπο με τον οποίο η εικονική μηχανή Java ασχολείται με αντικείμενα και πίνακες και συζητά τους σχετικούς κωδικούς bytecodes.
  • "Εξαιρέσεις" Περιγράφει τον τρόπο με τον οποίο η εικονική μηχανή Java αντιμετωπίζει εξαιρέσεις και συζητά τους σχετικούς bytecodes.
  • "Δοκιμάστε-Τέλος" Περιγράφει τον τρόπο με τον οποίο η εικονική μηχανή Java εφαρμόζει ρήτρες δοκιμής και συζητά τους σχετικούς κωδικούς bytecodes.
  • "Ροή ελέγχου" Περιγράφει τον τρόπο με τον οποίο η εικονική μηχανή Java εφαρμόζει τη ροή ελέγχου και συζητά τους σχετικούς κωδικούς bytecodes.
  • "Η Αρχιτεκτονική των Aglets" Περιγράφει τις εσωτερικές λειτουργίες του Aglets, της αυτόνομης τεχνολογίας λογισμικού της IBM που βασίζεται σε Java.
  • Το "The Point of Aglets" αναλύει την πραγματική χρησιμότητα κινητών πρακτόρων, όπως η Aglets, η αυτόνομη τεχνολογία λογισμικού της IBM που βασίζεται σε Java.
  • "Method Invocation and Return" Εξηγεί τον τρόπο με τον οποίο η εικονική μηχανή Java καλεί και επιστρέφει από μεθόδους, συμπεριλαμβανομένων των σχετικών bytecodes.

Αυτή η ιστορία, "Πώς η εικονική μηχανή Java εκτελεί συγχρονισμό νήματος" δημοσιεύθηκε αρχικά από το JavaWorld.