modelul de memorie Java pe scurt, specialist Java

Java de memorie model pe scurt


Cele două lucruri principale care introduc entropia în codul multifir - reordonarea și vizibilitatea.

Vizibilitate (vizibilitate)

Un fir poate la un moment dat stoca temporar valoarea unor câmpuri care nu se află în memoria principală și registrele sau cache-ul local al procesorului, astfel încât al doilea fir care rulează pe un alt procesor, citirea din memoria principală, nu se pot vedea cele mai recente modificări în domeniu. În schimb, în ​​cazul în care de ceva timp fluxul de lucru cu registrele locale și cache-uri, citirea datelor de acolo, el nu poate vedea imediat modificările făcute de un alt fir în memoria principală.

reordonare

Pentru a spori performanța procesorului / compilator poate fi reordonate câteva instrucțiuni / operații. Mai degrabă, din punctul de vedere al debitului, monitorizează punerea în aplicare a operațiunilor într-un alt curent, operațiunile pot fi efectuate nu în ordinea în care acestea sunt în codul sursă.

Astfel reorderinga același efect poate fi observat atunci când un flux pune primele rezultate de funcționare într-un registru sau local cache, iar rezultatul celei de a doua operațiune pune direct în memoria principală. Apoi, al doilea fir, referindu-se la memoria principală se poate vedea în primul rând rezultatul celei de a doua operație, prima și numai atunci, când toate registrele sau cache-urile sunt sincronizate cu memoria principală.

Un alt motiv pentru reordonare, poate consta în faptul că procesorul poate decide să schimbe ordinea operațiilor, de exemplu, în cazul în care consideră că o astfel de secvență este executată mai repede.

În practică, acest lucru poate avea consecințe foarte nefericite. Tot ce a spus, cred că problema în codul de mai jos este auto-explicativ:
Există încă important de reținut faptul că pentru operațiuni într-un singur fir, caietul de sarcini JVM permite face numai o astfel de reordonare, care are ca rezultat absolut aceleași rezultate ca și în cazul în care toate operațiunile au fost efectuate în modul specificat în codul sursă în ceea ce privește fluxul, în care codul efectuate. Ie într-un singur flux de reordonare văzut niciodată.

Happend-înainte

Memory Modelul Java a introdus o astfel de abstractizare ca se intampla-inainte. Aceasta înseamnă că, în cazul în care raportul de funcționare X este legată se întâmplă înainte de a-operarea cu Y, atunci întregul cod de operație urmată de starea Y, executat într-un singur fir vede toate modificările făcute de un alt fir înainte de o intervenție chirurgicală X.

Lista de operațiuni legate de atitudine se întâmplă înainte de a-:

Un punct foarte important: ca eliberare / monitor de captare și înregistrare scriere / citire la o atitudine variabilă volatilă legată se întâmplă înainte de a-, numai în cazul în care operațiunile sunt efectuate pe aceeași instanță de obiect.

De asemenea, este important să se înțeleagă că, în ceea ce se întâmplă, înainte de a implica doar două fluxuri de vizibilitate și reordonare fluxurile rămase nu pot spune nimic, atâta timp cât fiecare dintre ei nu va veni relație se întâmplă înainte de a-cu celălalt flux.

Chiar și în ceea ce privește se întâmplă, înainte de a exista un bonus foarte mare: acest raport nu numai că dă aspectul câmpurilor volatile sau rezultate ale operațiunilor, sigure monitorul sau Locke, dar, de asemenea, apariția tuturor tot ceea ce a fost făcut la eveniment hapens-înainte.

modelul de memorie Java pe scurt, specialist Java


Deci în figura de mai sus ThreadB garantat pentru a vedea o schimbare în y. a făcut ThreadA, deși nu este volatil și scris, are loc în afara blocului sincronizat.

Proprietățile descrise mai sus pot fi realizate în JVM după cum urmează: atunci când eliberați monitorul (înregistrare la o variabilă volatilă, și în continuare în jos lista) toate registrele și cache-urile locale ale procesorului sunt sincronizate cu memorie principală, iar la momentul capturii ulterioare Loka (citire variabilă volatilă, etc.) Procesor pe care al doilea flux invalidează cache-ul său și a citit toate cele mai recente date din memoria principală. De ce, atunci, este necesar să se sincronizeze pe același monitor, vă întreb? Da, pentru că numai în acest caz, va fi garantată printr-o ordine strictă, și anume, un al doilea fir este garantat să arunce memoria cache, imediat după prima sincronizare cu memoria principală.

Raportul se întâmplă înainte de a impune, de asemenea, constrângeri severe asupra reordonare. Din punctul de vedere al fluxului de Y toate operațiunile au avut loc la loc, înainte de punctul în care în fluxul de X poate fi considerată ca fiind operațiunea realizat în propriul său fir de execuție. Ie nici o reordonare logică în comparație directă ordinea în sursa în ceea ce privește fluxul Y nu poate fi.

Dacă ne uităm cu atenție la frontieră se întâmplă, înainte, în ceea ce privește fluxul de rearanjare Y, atunci nici o operație se află deasupra se întâmplă, înainte de limitele într-un curent X, nu pot fi executate sub limita se întâmplă, înainte ca urmare a reordonare, cu toate acestea, operațiunile sunt sub limitele admise împlinirea ei. Mai clar prezentat în figură.

modelul de memorie Java pe scurt, specialist Java

publicarea obiectelor

Această proprietate remarcabilă face antipattern dublu verificare blocare funcțional în cazul în care constructorul Singleton inițializează numai câmpul final.

Doar această proprietate rezolvă problema modelului de memorie anterior, în cazul în care utilizarea omniprezente dintr-o linie imuabile, strict vorbind nu funcționează întotdeauna.

Cum a această proprietate poate fi realizată de către JVM? Cred că JVM se va asigura că, la momentul înregistrării unui obiect de referință în memoria principală, toate valorile realizabile din domeniile finale expuse în timpul construcției, este deja sincronizat cu memoria principală. Astfel, orice flux de citire o referință la un obiect și este necesar pentru a citi toate valorile expuse maniera descrisă în timpul construcției.

reflecție

În ceea ce am auzit de la unul din personalul Oracle la JavaSE stand la ultimul JavaOne din Moscova, schimba câmpuri finale prin reflecție și după citirea lui ulterioară are loc prin bariera de memorie, astfel încât în ​​acest caz, este posibil să nu vă faceți griji cu privire la accesarea câmpuri finale din alte fluxuri . De fapt, mi se pare un pic ciudat și de neînțeles. Ruslan, care a auzit despre acest efect, împreună cu mine, se pare prea mult timp la acest gând, și a dat naștere la următorul post ca rezultat.

inițializare statică

câmpuri Atomicitate citire-scriere

JMM garantează Atomicitate câmpurilor nu lungi / duble de citire-scriere. Un volatil - absolut toate domeniile. Câmpul reprezentând referințe obiect, de asemenea, sunt întotdeauna scrise de citit atomically. Este de înțeles că, cu această specificație nu interzice să aibă înregistrarea Atomicitate lectură lung \ câmp dublu pentru mașini virtuale pe 64 de biți. Acest Atomicitate garantează că orice subiect în orice moment citit de la câmp sau valoarea implicită sau valoarea totală înregistrată acolo la un moment dat în timp, și niciodată nu vor găsi acolo unele resturi.