Programmering

Hvordan den virtuelle Java-maskine udfører trådsynkronisering

Alle Java-programmer er samlet i klassefiler, som indeholder bytekoder, maskinsproget for den virtuelle Java-maskine. Denne artikel tager et kig på, hvordan trådsynkronisering håndteres af den virtuelle Java-maskine, herunder de relevante bytekoder. (1.750 ord)

Denne måned er Under kølerhjelmen ser på trådsynkronisering på både Java-sproget og Java virtual machine (JVM). Denne artikel er den sidste i den lange række bytecode-artikler, jeg begyndte sidste sommer. Den beskriver de eneste to opkoder, der er direkte relateret til trådsynkronisering, de opkoder, der bruges til at indtaste og afslutte skærme.

Tråde og delte data

En af styrkerne ved Java-programmeringssproget er dets understøttelse af multithreading på sprogniveau. Meget af denne support er centreret om at koordinere adgang til data, der deles mellem flere tråde.

JVM organiserer dataene fra en kørende Java-applikation i flere runtime-dataområder: en eller flere Java-stakke, en bunke og et metodeområde. Se den første for en baggrund for disse hukommelsesområder Under kølerhjelmen artikel: "Den magre, gennemsnitlige virtuelle maskine."

Inde i den virtuelle Java-maskine tildeles hver tråd en Java-stak, som indeholder data, som ingen anden tråd har adgang til, inklusive de lokale variabler, parametre og returværdier for hver metode, som tråden har påberåbt sig. Dataene på stakken er begrænset til primitive typer og objektreferencer. I JVM er det ikke muligt at placere billedet af et faktisk objekt på stakken. Alle genstande ligger på bunken.

Der er kun én bunke inde i JVM, og alle tråde deler det. Bunken indeholder intet andet end objekter. Der er ingen måde at placere en ensom primitiv type eller objektreference på bunken - disse ting skal være en del af et objekt. Arrays ligger på dyngen, inklusive arrays af primitive typer, men i Java er arrays også objekter.

Udover Java-stakken og bunken er de andre steddata muligvis placeret i JVM metodeområde, som indeholder alle de klasse (eller statiske) variabler, der bruges af programmet. Metodeområdet svarer til stakken, idet det kun indeholder primitive typer og objektreferencer. I modsætning til stakken deles klassevariablerne i metodeområdet imidlertid af alle tråde.

Objekt- og klasselåse

Som beskrevet ovenfor indeholder to hukommelsesområder i den virtuelle Java-maskine data, der deles af alle tråde. Disse er:

  • Bunken, der indeholder alle objekter
  • Metodeområdet, der indeholder alle klassevariabler

Hvis flere tråde skal bruge de samme objekter eller klassevariabler samtidigt, skal deres adgang til dataene administreres korrekt. Ellers vil programmet have uforudsigelig opførsel.

For at koordinere delt dataadgang mellem flere tråde tilknytter den virtuelle Java-maskine en låse med hvert objekt og klasse. En lås er som et privilegium, som kun en tråd kan "besidde" ad gangen. Hvis en tråd vil låse et bestemt objekt eller en klasse, beder den JVM. På et eller andet tidspunkt efter at tråden beder JVM om en lås - måske meget snart, måske senere, muligvis aldrig - giver JVM låsen til tråden. Når tråden ikke længere har brug for låsen, returnerer den den til JVM. Hvis en anden tråd har anmodet om den samme lås, sender JVM låsen til den tråd.

Klasselåse implementeres faktisk som objektlåse. Når JVM indlæser en klassefil, opretter den en forekomst af klasse java.lang.Klasse. Når du låser en klasse, låser du faktisk klassens Klasse objekt.

Tråde behøver ikke at få en lås for at få adgang til instans- eller klassevariabler. Hvis en tråd får en lås, kan ingen anden tråd dog få adgang til de låste data, før den tråd, der ejer låsen, frigiver den.

Skærme

JVM bruger låse i forbindelse med skærme. En skærm er dybest set en værge, idet den overvåger en sekvens af kode og sørger for, at kun en tråd ad gangen udfører koden.

Hver skærm er knyttet til en objektreference. Når en tråd ankommer til den første instruktion i en kodeblok, der er under et monitorens øje, skal tråden opnå en lås på det refererede objekt. Tråden har ikke lov til at udføre koden, før den får låsen. Når den har opnået låsen, går tråden ind i blokken med beskyttet kode.

Når tråden forlader blokken, uanset hvordan den forlader blokken, frigør den låsen på det tilknyttede objekt.

Flere låse

En enkelt tråd får lov til at låse det samme objekt flere gange. For hvert objekt opretholder JVM antallet af gange, objektet er blevet låst. Et ulåst objekt har en optælling på nul. Når en tråd får låsen for første gang, øges optællingen til en. Hver gang tråden får en lås på det samme objekt, øges et antal. Hver gang tråden frigør låsen, mindskes antallet. Når optællingen når nul, frigøres låsen og gøres tilgængelig for andre tråde.

Synkroniserede blokke

I Java-sprogterminologi kaldes koordinationen af ​​flere tråde, der skal have adgang til delte data synkronisering. Sproget giver to indbyggede måder at synkronisere adgang til data på: med synkroniserede udsagn eller synkroniserede metoder.

Synkroniserede udsagn

For at oprette en synkroniseret sætning bruger du synkroniseret nøgleord med et udtryk, der evalueres til en objektreference, som i omvendt rækkefølge() nedenstående metode:

klasse KitchenSync {privat int [] intArray = ny int [10]; ugyldig reverseOrder () {synkroniseret (dette) {int halfWay = intArray.length / 2; for (int i = 0; i <halfWay; ++ i) {int upperIndex = intArray.length - 1 - i; int gemme = intArray [upperIndex]; intArray [upperIndex] = intArray [i]; intArray [i] = gem; }}}}

I ovenstående tilfælde vil udsagnene indeholdt i den synkroniserede blok ikke blive udført, før der er erhvervet en lås på det aktuelle objekt (det her). Hvis i stedet for en det her reference, udtrykket gav en henvisning til et andet objekt, låsen tilknyttet det objekt ville blive erhvervet, før tråden fortsatte.

To opkoder, monitorenter og monitorexit, bruges til synkroniseringsblokke inden for metoder, som vist i nedenstående tabel.

Tabel 1. Skærme

OpkodeOperand (er)Beskrivelse
monitorenteringenpop objectref, erhverv den lås, der er knyttet til objectref
monitorexitingenpop objectref, frigør låsen, der er knyttet til objectref

Hvornår monitorenter er stødt på af den virtuelle Java-maskine, får den låsen til det objekt, der henvises til af objektref på stakken. Hvis tråden allerede ejer låsen til det pågældende objekt, øges et antal. Hver gang monitorexit udføres for tråden på objektet, tælles antallet ned. Når optællingen når nul, frigives monitoren.

Se på bytekodesekvensen genereret af omvendt rækkefølge() metode til KitchenSync klasse.

Bemærk, at en fangstklausul sikrer, at det låste objekt låses op, selvom en undtagelse kastes fra den synkroniserede blok. Uanset hvordan den synkroniserede blok afsluttes, frigøres objektlåsen, der blev erhvervet, da tråden kom ind i blokken, helt sikkert.

Synkroniserede metoder

For at synkronisere en hel metode skal du blot medtage synkroniseret nøgleord som en af ​​metodekvalifikationerne, som i:

klasse HeatSync {privat int [] intArray = ny int [10]; synkroniseret ugyldig reverseOrder () {int halfWay = intArray.length / 2; for (int i = 0; i <halfWay; ++ i) {int upperIndex = intArray.length - 1 - i; int gemme = intArray [upperIndex]; intArray [upperIndex] = intArray [i]; intArray [i] = gem; }}}

JVM bruger ikke nogen specielle opkoder til at påkalde eller vende tilbage fra synkroniserede metoder. Når JVM løser den symbolske henvisning til en metode, bestemmer den, om metoden er synkroniseret. Hvis det er tilfældet, erhverver JVM en lås, inden den påberåber sig metoden. For en instansmetode erhverver JVM den lås, der er knyttet til det objekt, hvorpå metoden påberåbes. For en klassemetode erhverver den den lås, der er knyttet til den klasse, som metoden tilhører. Når en synkroniseret metode er afsluttet, uanset om den fuldføres ved at vende tilbage eller ved at kaste en undtagelse, frigøres låsen.

Kommer næste måned

Nu hvor jeg har gennemgået hele bytecode-instruktionssættet, udvider jeg rækkevidden af ​​denne kolonne til at omfatte forskellige aspekter eller applikationer af Java-teknologi, ikke kun den virtuelle Java-maskine. Næste måned begynder jeg en serie med flere dele, der giver et dybtgående overblik over Java's sikkerhedsmodel.

Bill Venners har skrevet professionelt software i 12 år. Baseret i Silicon Valley leverer han softwarekonsulent- og træningstjenester under navnet Artima Software Company. Gennem årene har han udviklet software til forbrugerelektronik, uddannelse, halvleder og livsforsikringsindustri. Han har programmeret på mange sprog på mange platforme: monteringssprog på forskellige mikroprocessorer, C på Unix, C ++ på Windows, Java på nettet. Han er forfatter til bogen: Inside the Java Virtual Machine, udgivet af McGraw-Hill.

Lær mere om dette emne

  • Bogen Specifikationen for den virtuelle Java-maskine (//www.aw.com/cp/lindholm-yellin.html), af Tim Lindholm og Frank Yellin (ISBN 0-201-63452-X), en del af Java-serien (//www.aw.com/cp /javaseries.html), fra Addison-Wesley, er den definitive Java-virtuelle maskinreference.
  • Tidligere artikler "Under hætte":
  • "Den magre, gennemsnitlige virtuelle maskine" Giver en introduktion til den virtuelle Java-maskine.
  • "Java Class File Lifestyle" Giver en oversigt over Java-klassefilen, det filformat, som alle Java-programmer er samlet i.
  • "Java's Garbage-Collected Heap" Giver et overblik over skraldopsamling generelt og skraldespildet bunke på den virtuelle Java-maskine i særdeleshed.
  • "Bytecode Basics" Introducerer bytecodes på den virtuelle Java-maskine og diskuterer især primitive typer, konverteringsoperationer og stack-operationer.
  • "Flydepunktsaritmetik" Beskriver den virtuelle Java-maskines understøttelse af flydepunkter og de bytekoder, der udfører operationer med flydende punkt.
  • "Logik og aritmetik" Beskriver den virtuelle Java-maskines understøttelse af logisk og heltal aritmetik og de relaterede bytekoder.
  • "Objekter og arrays" Beskriver, hvordan den virtuelle Java-maskine håndterer objekter og arrays, og diskuterer de relevante bytekoder.
  • "Undtagelser" Beskriver, hvordan den virtuelle Java-maskine håndterer undtagelser, og diskuterer de relevante bytekoder.
  • "Prøv-Endelig" Beskriver, hvordan den virtuelle Java-maskine implementerer prøve-endelige klausuler, og diskuterer de relevante bytekoder.
  • "Control Flow" Beskriver, hvordan den virtuelle Java-maskine implementerer kontrolflow og diskuterer de relevante bytekoder.
  • "Arkitekturen af ​​aglets" Beskriver den indre funktion af Aglets, IBMs autonome Java-baserede softwareagentteknologi.
  • "Point of Aglets" Analyserer den virkelige nytte af mobile agenter såsom Aglets, IBMs autonome Java-baserede softwareagentteknologi.
  • "Method Invocation and Return" Forklarer, hvordan den virtuelle Java-maskine påberåber sig og vender tilbage fra metoder, inklusive de relevante bytecodes.

Denne historie, "Hvordan den virtuelle Java-maskine udfører trådsynkronisering", blev oprindeligt udgivet af JavaWorld.