Programování

Jak virtuální stroj Java provádí synchronizaci vláken

Všechny programy Java jsou kompilovány do souborů tříd, které obsahují bytecodes, jazyk stroje virtuálního stroje Java. Tento článek pojednává o tom, jak synchronizaci vláken zpracovává virtuální stroj Java, včetně příslušných bajtových kódů. (1750 slov)

Tento měsíc Under The Hood zkoumá synchronizaci vláken v jazyce Java i na virtuálním stroji Java (JVM). Tento článek je posledním z dlouhé řady článků o bytecode, které jsem začal loni v létě. Popisuje pouze dva operační kódy přímo související se synchronizací vláken, operační kódy používané pro vstup a výstup z monitorů.

Vlákna a sdílená data

Jednou ze silných stránek programovacího jazyka Java je jeho podpora multithreadingu na jazykové úrovni. Velká část této podpory se soustředí na koordinaci přístupu k datům sdíleným mezi více vlákny.

JVM organizuje data spuštěné aplikace Java do několika runtime datových oblastí: jeden nebo více zásobníků Java, halda a oblast metod. Pro pozadí těchto paměťových oblastí viz první Pod kapotou článek: „The lean, mean virtual machine.“

Uvnitř virtuálního stroje Java je každé vlákno uděleno Zásobník Java, který obsahuje data, k nimž nemá přístup žádné jiné vlákno, včetně místních proměnných, parametrů a návratových hodnot každé metody, kterou vlákno vyvolalo. Data v zásobníku jsou omezena na primitivní typy a odkazy na objekty. V JVM není možné umístit obrázek skutečného objektu do zásobníku. Všechny objekty jsou umístěny na haldě.

Je jen jeden halda uvnitř JVM a všechna vlákna jej sdílejí. Halda neobsahuje nic jiného než objekty. Neexistuje způsob, jak umístit osamělý primitivní typ nebo odkaz na objekt na haldu - tyto věci musí být součástí objektu. Pole jsou umístěna na haldě, včetně polí primitivních typů, ale v Javě jsou pole také objekty.

Kromě Java stacku a haldy mohou být v JVM další data o místě oblast metody, který obsahuje všechny třídní (nebo statické) proměnné používané programem. Oblast metody je podobná zásobníku v tom, že obsahuje pouze primitivní typy a odkazy na objekty. Na rozdíl od zásobníku jsou však proměnné třídy v oblasti metody sdíleny všemi vlákny.

Zámky objektů a tříd

Jak je popsáno výše, dvě oblasti paměti ve virtuálním stroji Java obsahují data sdílená všemi vlákny. Tyto jsou:

  • Halda, která obsahuje všechny objekty
  • Oblast metody, která obsahuje všechny proměnné třídy

Pokud více vláken potřebuje současně používat stejné objekty nebo proměnné třídy, musí být jejich přístup k datům správně spravován. Jinak bude mít program nepředvídatelné chování.

Ke koordinaci sdíleného přístupu k datům mezi více vlákny přidruží virtuální stroj Java a zámek s každým objektem a třídou. Zámek je jako privilegium, které může „vlastnit“ vždy jen jedno vlákno. Pokud vlákno chce zamknout určitý objekt nebo třídu, zeptá se JVM. V určitém okamžiku poté, co vlákno požádá JVM o zámek - možná velmi brzy, možná později, možná nikdy - JVM dá zámek vláknu. Když vlákno již zámek nepotřebuje, vrátí jej JVM. Pokud jiné vlákno požadovalo stejný zámek, předá JVM zámek tomuto vláknu.

Zámky třídy jsou ve skutečnosti implementovány jako zámky objektů. Když JVM načte soubor třídy, vytvoří instanci třídy java.lang.Class. Když zamknete třídu, ve skutečnosti ji zamknete Třída objekt.

Vlákna nemusí získat zámek pro přístup k proměnným instance nebo třídy. Pokud vlákno získá zámek, ale žádné jiné vlákno nebude mít přístup k uzamčeným datům, dokud jej vlákno, které vlastní zámek, neuvolní.

Monitory

JVM používá zámky ve spojení s monitory. Monitor je v zásadě strážcem v tom, že hlídá sekvenci kódu a zajišťuje, aby kód prováděl pouze jeden podproces.

Každý monitor je přidružen k odkazu na objekt. Když vlákno dorazí na první instrukci v bloku kódu, který je pod dohledem monitoru, vlákno musí získat zámek na odkazovaný objekt. Vlákno nesmí provádět kód, dokud nezíská zámek. Jakmile získal zámek, vlákno vstoupí do bloku chráněného kódu.

Když vlákno opustí blok, bez ohledu na to, jak opustí blok, uvolní zámek přidruženého objektu.

Více zámků

Jeden podproces je povolen k uzamčení stejného objektu vícekrát. Pro každý objekt udržuje JVM počet, kolikrát byl objekt uzamčen. Odemčený objekt má počet nula. Když vlákno získá zámek poprvé, počet se zvýší na jednu. Pokaždé, když vlákno získá zámek na stejný objekt, zvýší se počet. Pokaždé, když vlákno uvolní zámek, počet se sníží. Když počet dosáhne nuly, zámek se uvolní a zpřístupní jiným vláknům.

Synchronizované bloky

V terminologii jazyka Java se nazývá koordinace více vláken, která musí mít přístup ke sdíleným datům synchronizace. Jazyk poskytuje dva integrované způsoby synchronizace přístupu k datům: pomocí synchronizovaných příkazů nebo synchronizovaných metod.

Synchronizované příkazy

Chcete-li vytvořit synchronizovaný příkaz, použijte synchronizované klíčové slovo s výrazem, který se vyhodnotí jako odkaz na objekt, jako v obrácené pořadí() níže uvedená metoda:

třída KitchenSync {private int [] intArray = new int [10]; void reverseOrder () {synchronized (this) {int halfWay = intArray.length / 2; for (int i = 0; i <halfWay; ++ i) {int upperIndex = intArray.length - 1 - i; int save = intArray [upperIndex]; intArray [upperIndex] = intArray [i]; intArray [i] = uložit; }}}}

Ve výše uvedeném případě nebudou příkazy obsažené v synchronizovaném bloku provedeny, dokud nezískáte zámek na aktuálním objektu (tento). Pokud místo a tento reference, výraz přinesl odkaz na jiný objekt, zámek spojený s tímto objektem by byl získán před pokračováním vlákna.

Dva operační kódy monitorovací centrum a monitorexit, se používají pro synchronizační bloky v rámci metod, jak je uvedeno v následující tabulce.

Tabulka 1. Monitory

Operační kódOperand (s)Popis
monitorovací centrumžádnýpop objectref, získejte zámek spojený s objectref
monitorexitžádnýpop objectref, uvolnit zámek spojený s objectref

Když monitorovací centrum narazí na virtuální stroj Java, získá zámek pro objekt, na který odkazuje stackref objectref. Pokud vlákno již vlastní zámek pro daný objekt, zvýší se počet. Pokaždé monitorexit je provedeno pro vlákno na objektu, počet je snížen. Když počet dosáhne nuly, monitor se uvolní.

Podívejte se na sekvenci bajtových kódů vygenerovanou obrácené pořadí() metoda KitchenSync třída.

Všimněte si, že klauzule catch zajišťuje, že uzamčený objekt bude odemčen, i když je v synchronizovaném bloku vyvolána výjimka. Bez ohledu na to, jak je synchronizovaný blok ukončen, zámek objektu získaný při vstupu vlákna do bloku bude definitivně uvolněn.

Synchronizované metody

Chcete-li synchronizovat celou metodu, stačí zahrnout synchronizované klíčové slovo jako jeden z kvalifikátorů metody, jako v:

třída HeatSync {private int [] intArray = new int [10]; synchronized void reverseOrder () {int halfWay = intArray.length / 2; for (int i = 0; i <halfWay; ++ i) {int upperIndex = intArray.length - 1 - i; int save = intArray [upperIndex]; intArray [upperIndex] = intArray [i]; intArray [i] = uložit; }}}

JVM nepoužívá žádné speciální operační kódy k vyvolání nebo návratu ze synchronizovaných metod. Když JVM vyřeší symbolický odkaz na metodu, určí, zda je metoda synchronizována. Pokud ano, JVM získá zámek před vyvoláním metody. U metody instance JVM získá zámek přidružený k objektu, na který je metoda vyvolána. U metody třídy získává zámek přidružený ke třídě, do které metoda patří. Po dokončení synchronizované metody, ať už se dokončí vrácením nebo vyvoláním výjimky, se zámek uvolní.

Příští měsíc

Nyní, když jsem prošel celou instrukční sadou bytecode, budu rozšiřovat rozsah tohoto sloupce tak, aby zahrnoval různé aspekty nebo aplikace technologie Java, nejen virtuální stroj Java. Příští měsíc zahájím vícedílnou sérii, která poskytne podrobný přehled bezpečnostního modelu Java.

Bill Venners píše software profesionálně již 12 let. Se sídlem v Silicon Valley poskytuje softwarové poradenství a školení pod názvem Artima Software Company. V průběhu let vyvinul software pro spotřební elektroniku, vzdělávání, polovodiče a odvětví životního pojištění. Programoval v mnoha jazycích na mnoha platformách: montážní jazyk na různých mikroprocesorech, C na Unixu, C ++ na Windows, Java na webu. Je autorem knihy: Inside the Java Virtual Machine, vydané nakladatelstvím McGraw-Hill.

Další informace o tomto tématu

  • Kniha Specifikace virtuálního stroje Java (//www.aw.com/cp/lindholm-yellin.html), Tim Lindholm a Frank Yellin (ISBN 0-201-63452-X), součást The Java Series (//www.aw.com/cp /javaseries.html), z Addison-Wesley, je definitivní odkaz na virtuální stroj Java.
  • Předchozí články „Under the Hood“:
  • „The Lean, Mean Virtual Machine“ Představuje úvod do virtuálního stroje Java.
  • „Životní styl souboru třídy Java“ Poskytuje přehled souboru třídy Java, formátu souboru, do kterého jsou kompilovány všechny programy Java.
  • „Hromada shromážděných odpadků Java“ Poskytuje přehled sběru odpadků obecně a zvláště hromady odpadků virtuálního počítače Java.
  • „Bytecode Basics“ Představuje bajtkódy virtuálního stroje Java a popisuje zejména primitivní typy, operace převodu a operace zásobníku.
  • „Floating Point Arithmetic“ Popisuje podporu plovoucí desetinné čárky virtuálního stroje Java a bajtové kódy, které provádějí operace s plovoucí desetinnou čárkou.
  • „Logic and Arithmetic“ Popisuje podporu virtuálního počítače Java pro logickou a celočíselnou aritmetiku a související bajtové kódy.
  • „Objekty a pole“ Popisuje, jak virtuální stroj Java pracuje s objekty a poli, a popisuje příslušné bajtové kódy.
  • „Výjimky“ Popisuje, jak virtuální stroj Java pracuje s výjimkami, a popisuje příslušné bajtové kódy.
  • „Try-Finally“ Popisuje, jak virtuální stroj Java implementuje klauzule try-finally, a popisuje příslušné bajtové kódy.
  • „Řídicí tok“ Popisuje, jak virtuální stroj Java implementuje řídicí tok, a popisuje příslušné bajtové kódy.
  • „The Architecture of Aglets“ Popisuje vnitřní fungování Aglets, autonomní technologie softwarového agenta založené na Javě od IBM.
  • „The Point of Aglets“ Analyzuje skutečnou užitečnost mobilních agentů, jako je Aglets, autonomní technologie softwarových agentů založené na Javě od IBM.
  • „Vyvolání a vrácení metody“ Vysvětluje, jak virtuální stroj Java vyvolává a vrací z metod, včetně příslušných bajtových kódů.

Tento příběh, „Jak virtuální stroj Java provádí synchronizaci vláken“, původně publikoval JavaWorld.