Model de memorie Java

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 16 iulie 2022; verificarea necesită 1 editare .

Modelul de memorie Java ( JMM ) descrie comportamentul thread -urilor în mediul de rulare Java .  Modelul de memorie face parte din semantica limbajului Java și descrie la ce se poate și nu ar trebui să se aștepte un programator atunci când dezvoltă software nu pentru o anumită mașină Java, ci pentru Java în ansamblu.

Modelul original de memorie Java (care include în special „memoria percolocală”), dezvoltat în 1995, este considerat un eșec: multe optimizări nu pot fi făcute fără a pierde garanția siguranței codului. În special, există mai multe opțiuni pentru a scrie „ cu o singură mână ” cu mai multe fire: [1]

J2SE 5.0 (30 septembrie 2004) a introdus un nou model de memorie dezvoltat prin intermediul procesului comunitar Java numit JSR-133 [2] [3] . A reflectat mai bine modul în care funcționează procesoarele și compilatoarele moderne, iar alte limbaje au preluat idei din modelul Java. Principalele contribuții la crearea sa au fost aduse de Sarita Adwe , Jeremy Mason și Bill Pugh [4] .

Fundal

Limbajul de programare Java vă permite să scrieți programe cu mai multe fire. Deoarece Java poate rula pe o mare varietate de procesoare și sisteme de operare, sincronizarea firelor este deosebit de dificilă. Pentru ca programatorul să tragă câteva concluzii despre comportamentul programelor, dezvoltatorii Java au decis să definească clar diferitele comportamente ale tuturor programelor Java.

Pe computerele moderne, codul nu este executat în ordinea în care este scris de dragul vitezei. Permutarea se face de către compilator, procesor și subsistemul de memorie. Pe mașinile multiprocesor, fiecare nucleu poate avea propriul cache care nu este sincron cu memoria principală. Aceasta înseamnă că procesoare diferite pot avea valori diferite ale aceleiași variabile în același timp. Când firele de execuție interacționează mult între ele, acest lucru este de obicei nedorit: este nevoie de mult timp pentru a fi la curent cu ceea ce a făcut celălalt procesor.

În plus, într-un mediu cu un singur thread, este suficient să ceri sistemului să execute programul „pseudo-secvențial” - unui observator care vede doar I/O , se va părea că toate acțiunile sunt efectuate în ordinea în care acestea au apărut în program, chiar dacă nu sunt. Cu toate acestea, oricine poate „să se uite” în memoria computerului – inclusiv un alt fir – toate aceste „smecherii” vor fi observate. Luați în considerare două fire care execută simultan un astfel de cod ( xși yinițial zerouri).

Fluxul 1 Fluxul 2
x = 1; int r1 = y;
y=2; int r2 = x;

Dacă nu există permutări, iar firul 2 citește y=2, este garantat să fie x=1: la urma urmei, scrierea în xeste efectuată înainte de scrierea în y. Cu o permutare, o situație aparent paradoxală se dovedește a fi posibilă: r1=2, r2=0.

JMM permite acest comportament al programelor multithreaded, dar descrie când astfel de permutări sunt posibile. Astfel, modelul de memorie Java impune restricții privind interacțiunea firelor de execuție pentru a nu pierde posibilele optimizări și, în același timp, permite programelor multi-threaded să se comporte fiabil și previzibil acolo unde este nevoie. Programatorul poate face orice inferențe despre ordinea în care codul este executat pe o mașină multithreaded , chiar și în ciuda optimizărilor făcute de compilator, procesor și cache.

Model de memorie

Regula #1: Programele cu un singur thread rulează pseudo-secvențial. Aceasta înseamnă: în realitate, procesorul poate efectua mai multe operații pe ceas, schimbându-le în același timp ordinea, totuși, toate dependențele de date rămân, astfel încât comportamentul nu diferă de secvenţial.

Regula numărul 2: nu există valori de nicăieri. Citirea oricărei variabile (cu excepția non- volatile longși double, pentru care această regulă poate să nu fie adevărată) va returna fie valoarea implicită (zero), fie ceva scris acolo de o altă comandă.

Și regula numărul 3: restul evenimentelor sunt executate în ordine, dacă sunt conectate printr-o relație strictă de ordine parțială „se execută înainte” ( în engleză  se întâmplă înainte ).

„Alergă înainte”

„Happens before” ( în engleză  se întâmplă înainte ) este o relație strictă de ordine parțială (antireflexivă, antisimetrică, tranzitivă) introdusă între comenzi atomice ( ++și --nu atomice), inventată de Leslie Lamport și nu înseamnă „fizic înainte”. Înseamnă că a doua echipă va fi „la cunoștință” de modificările făcute de prima.

În special, una este efectuată înaintea celeilalte pentru astfel de operațiuni (lista nu este exhaustivă):

Influență

Datorită introducerii pe scară largă a sistemelor multi-threaded și paralele, a fost necesar un set de instrumente cu o semantică clară. Modelul de memorie Java a fost prima încercare de a dezvolta un model de comunicare inter-thread cuprinzător pentru un limbaj de programare major [9] .

În C++03 , singura notă despre multithreading este că volatile-variabilele nu au nicio optimizare a vitezei de acces. De asemenea, acest lucru nu a fost suficient pentru a utiliza întreaga putere a compilatorului/procesorului de rearanjare și pentru a nu obține o eroare legată de execuția necorespunzătoare a unei comenzi. Un model de memorie similar a fost inclus în C++11 [10] .

Vezi și

Note

  1. Declarația „Încuierea dublu verificată este spartă” . Preluat la 21 iulie 2013. Arhivat din original la 6 martie 2012.
  2. 1 2 Goetz, Brian Fixing the Java Memory Model, Part 2 (downlink) (24 februarie 2004). Consultat la 18 octombrie 2010. Arhivat din original pe 8 ianuarie 2007. 
  3. Jeremy Manson și Brian Goetz. Întrebări frecvente JSR 133 (Java Memory Model) (februarie 2004). — « Modelul de memorie Java descrie ce comportamente sunt legale în codul cu mai multe fire și cum pot interacționa firele prin memorie. Descrie relația dintre variabilele dintr-un program și detaliile de nivel scăzut ale stocării și regăsirii lor în și din memorie sau registre într-un sistem informatic real. Face acest lucru într-un mod care poate fi implementat corect folosind o mare varietate de hardware și o mare varietate de optimizări ale compilatorului. ". Data accesului: 18 octombrie 2010. Arhivat din original la 4 septembrie 2013.
  4. James Gosling, Bill Joy, Guy L. Jr. Steele, Gilad Bracha, Alex Buckley. Specificația limbajului Java, Java SE 7 Edition. - Pearson Education, 2013. - ISBN 978-0-13-326032-8 .
  5. Sincronizarea și modelul de memorie Java . Preluat la 21 iulie 2013. Arhivat din original la 11 mai 2013.
  6. Cartea de bucate JSR-133 (link descendent) . Consultat la 18 iulie 2013. Arhivat din original la 25 septembrie 2013. 
  7. Nicăieri, cu excepția constructorului, finalnu puteți scrie în câmpuri.
  8. >note de lucru: Garanții pentru câmpurile finale . Consultat la 22 iulie 2013. Arhivat din original la 16 ianuarie 2015.
  9. Goetz, Brian Fixing the Java Memory Model, Part 1 (downlink) (24 februarie 2004). Consultat la 17 februarie 2008. Arhivat din original pe 13 august 2009. 
  10. Boehm, Hans Threads și modelul de memorie pentru C++ (downlink) . Data accesului: 17 februarie 2008. Arhivat din original la 4 septembrie 2013. 

Link -uri