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] .
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.
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 ).
„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ă):
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] .
Java | |
---|---|
Platforme | |
Sun Technologies | |
Tehnologii cheie ale terților | |
Poveste |
|
Proprietățile limbajului | |
Limbaje de scripting |
|
conferințe Java |
|