English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Sentimenti di studio sulla memoria del modello Java JMM

A volte l'ottimizzazione del compilatore o del processore può causare che il runtime sia diverso da quello che ci si aspettava, per questo Java ha imposto alcune limitazioni ai compilatori e ai processori, il modello di memoria della JVM (JMM) astrae questi, in modo che quando si scrive il codice non si debba considerare così tanti dettagli di basso livello, e garantisce che "se si scrive un programma seguendo le regole della JMM, il risultato della sua esecuzione sarà sempre corretto".

Struttura astratta della JMM

In Java, tutte le istanze e le variabili statiche sono memorizzate nella memoria heap, la memoria heap può essere condivisa tra i thread, questa parte è anche chiamataVariabili condiviseE le variabili locali, i parametri delle definizioni di metodo e i parametri di gestione delle eccezioni sono nello stack, la memoria dello stack non è condivisa tra i thread.

E a causa dell'ottimizzazione del compilatore e del processore, può causare problemi di visibilità delle variabili condivise, come nei processori multi-core (multi-processor), dove le thread possono essere eseguite su diversi processori.L'inconsistenza della cache tra i processori può causare problemi di visibilità delle variabili condivise, è possibile che due thread vedano valori diversi per la stessa variabile.

La JMM astrae le ottimizzazioni hardware fatte in ciascuna thread come se avesse una memoria locale. Quando è necessario leggere e scrivere variabili condivise, copiare una copia dalla memoria principale alla memoria locale. Quando si scrive una variabile condivisa, prima scrivere nella memoria locale e poi aggiornare alla memoria principale in un momento futuro. Quando si legge di nuovo una variabile condivisa, leggere solo dalla memoria locale.

In questo modo, la comunicazione tra thread richiede due passaggi:

Thread di scrittura: aggiornare la memoria locale alla memoria principale Thread di lettura: leggere il valore aggiornato dalla memoria principale

In questo modo, c'è un ritardo tra la scrittura e la lettura: quando il locale memoria viene aggiornato nella memoria principale? Questo porta a problemi di visibilità, e diversi thread possono vedere variabili condivise diverse.

Regola di avvenire prima di

In senso letterale, il significato di 'avviene prima di' è 'avviene prima'. Questa è una regola stabilita dalla Java per l'ordine di esecuzione del programma, che deve essere seguita per realizzare la sincronizzazione. In questo modo, il programmatore deve solo scrivere un programma di sincronizzazione corretto, e la regola di avvenire prima di garantisce che il risultato dell'esecuzione non sia sbagliato.

A avviene prima di B, non solo significa che A deve essere eseguito prima di B, ma anche che il risultato dell'esecuzione di A è visibile a B, il che garantisce la visibilità.

A avviene prima di B, non significa necessariamente che A deve essere eseguito prima di B. Se A e B si alternano, il risultato dell'esecuzione è ancora corretto, quindi è permesso che il compilatore e il processore ottimizzino e riordinino. Pertanto, finché il risultato del programma è corretto, non c'è problema con come il compilatore e il processore ottimizzano e riordinano, sono tutti buoni.

Regola di avvenire prima di

Regola di sequenza del programma: nell'ordine delle operazioni in una thread, l'operazione anteriore avviene prima dell'operazione successiva. Regola dei lock: per lo stesso lock, la liberazione avviene prima dell'acquisizione. Regola del dominio volatile: scrivere un variabile volatile, l'operazione di lettura successiva di questo volatile variabile avviene prima. Proprietà transitiva: se A avviene prima di B, e B avviene prima di C, allora A avviene prima di C. Regola di start(): se la thread A esegue ThreadB.start(), allora ThreadB.start() avviene prima di qualsiasi operazione nella thread B. Regola di join(): se la thread A esegue ThreadB.join(), allora tutte le operazioni nella thread B avvengono prima di ThreadB.join().

Questo esempio è utile per comprendere il concetto di happens-before

double pi = 3.14; //A
double r = 1.0; //B
double area = pi * r * r; //C

Ci sono tre relazioni di happens-before qui, regola 1 e 2 sono regole di sequenza del programma, regola 3 è derivata da regole di trasmissione:

A happens-before B, B happens-before C, A happens-before C

C dipende da A e B, ma né A né B dipendono da nessuno. Quindi, anche se A e B vengono riordinati, il risultato dell'esecuzione non cambia, questo riordino è eseguito dal JMM.

I risultati dell'ordine di esecuzione delle due seguenti sono entrambi corretti.

Questo è tutto il contenuto che abbiamo raccolto per voi sui punti di apprendimento del modello di memoria Java JMM, ulteriori domande possono essere discusse nei commenti sottostanti, grazie per il tuo supporto al tutorial di urla.

Dichiarazione: il contenuto di questo articolo è stato raccolto da Internet, il copyright è della proprietà del rispettivo autore, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, questo sito rimuoverà immediatamente i contenuti sospetti di violazione del copyright.

Ti potrebbe interessare