2016-02-14 16 views
5

Molte persone hanno fatto domande simili come questa, ma nessuna delle loro risposte mi ha soddisfatto. Le uniche due Riordinamento delle regole che io sono molto sicuro sono i segue:Quali sono i metodi di riordino validi per Java sincronizzati?

  1. Operations all'interno del blocco sincronizzato (o semplicemente chiamare sezione critica) sono ammessi da riordinare, a patto che conferma alla semantica come se seriale.
  2. Le operazioni (incluse le letture e le scritture ) sono non consentite da spostare (riordinate) fuori dalla sezione critica.

Tuttavia, per le operazioni precedenti o successive al blocco sincronizzato, possono essere spostate nella sezione critica? Per questo problema, ho trovato un po 'contrario. Ad esempio, il cookbook detto che il compilatore inserirà alcune barriere dopo la MonitorEnter e prima della MonitorExit:

MonitorEnter 
(any other needed instructions go here) 
[LoadLoad] <===MB1:Inserted memory barrier 
[LoadStore] <===MB2:Inserted memory barrier 
(Begin of critical section) 

.... 
(end of critical section) 
[LoadStore] <===MB3:Inserted memory barrier 
[StoreStore] <===MB4:Inserted memory barrier 
(any other needed instructions go here) 
MonitorExit 

Secondo essere superiore posizionamento fatta dal compilatore e indicato di seguito pseudo codice:

Load a; 
    Load b; 
    Store 1; 
    Store 2; 
    MonitorEnter 
    (any other needed instructions go here) 
    [LoadLoad] <===MB1 
    [LoadStore] <===MB2 
    (Begin of critical section) 

    .... 
    (end of critical section) 
    [LoadStore] <===MB3 
    [StoreStore] <===MB4 
    (any other needed instructions go here) 
    MonitorExit 
    Store 3; 
    Store 4; 
    Load c; 
    Load d; 

Secondo il ricettario e le regole di prevenzione del riordino imposte da tali XY (X è Load o Store, Y is Load o Store), mi sembra che il riordino valido/non valido sia il seguente:

Comprensione 1: Qualsiasi sto res (Store 3 e Store 4 qui) dopo che MonitorExit può NON essere spostato verso l'alto prima di MB3 e MB4, a causa dell'esistenza di un LoadStore (MB3) seguito da un Store Store (MB4). Vale a dire i negozi dopo che MonitorExit non può essere spostato nella sezione critica. Tuttavia, è possibile essere spostato verso l'alto dopo MB4, vale a dire l'area della staffa.

Capire 2: Eventuali carichi (caricare una e carico b qui) prima della MonitorEnter può NON essere spostato verso il basso dopo MB2 e MB1, a causa dell'esistenza di un LoadLoad (MB1) seguito da un LoadLoad (MB2). Vale a dire carichi prima che MonitorEnter non possa essere spostato nella critica. Tuttavia, è possibile spostare dopo MB2, ovvero l'area della staffa.

Understanding 3: Qualsiasi carico (carico C e carico d qui) dopo il MonitorExit può essere spostati prima della MonitorExit, compresa la sezione critica e la zona del movimento, ma non può superare il MonitorEnter.

Capire 4: Tutti i negozi (negozio di 1 e 2 Conservare qui) prima della MonitorEnter possono essere spostati verso il basso dopo la MonitorEnter, compresa la sezione critica e la zona del movimento, ma non può superare il MonitorExit.

Tuttavia, tutta la comprensione o reclamo sopra vedono in contrasto con quello che ha detto Jeremy Manson nel suo blog, dove ha sostenuto che danno sottostante Codice:

x = 1;//Store 
synchronized(o) { 
z = z + 1; 
} 
y = 1//Store 

Riordino che producono sottostante Codice è ammessi:

synchronized(o){ 
y = 1;//I added this comment:Store moved inside the critical section 
z = z + 1; 
x = 1;//I added this comment:Store moved inside the critical section 
} 

Secondo Understanding 1, "y = 1" non può essere spostato all'interno della sezione critica, Così ho solo era confusa, che è quella corretta e complet e?

+0

http://jeremymanson.blogspot.fi/2007/05/roach-motels-and-java-memory-model.html – ale64bit

risposta

0

Il riordinamento non interessa le barriere della memoria. Anche se il compilatore inserisce sempre la barriera di memoria più forte tra due istruzioni, questi sono comunque permessi a prescindere.

Ora, data una sequenza di istruzioni, probabilmente dopo essere stata riordinata dalla sequenza originale, il compilatore deve inserire le corrette barriere di memoria tra alcune istruzioni.

Ad esempio, in una sequenza di istruzioni originale

volatile store x 
normal store y 

non necessita barriera memoria tra le due istruzioni.

Tuttavia, il compilatore può scegliere di riordinare a

normal store y 
volatile store x 

quindi una barriera StoreStore è necessario tra le due istruzioni. La CPU ha solo un'istruzione "store", nessun concetto di archivio normale/volatile. E la CPU potrebbe avere negozi fuori ordine. È la semantica Java che richiede che un'altra CPU non debba osservare l'effetto di store x prima dell'effetto di volatile store y; quindi viene utilizzato un Store Store per indicare alla CPU di memorizzarli in ordine.

(Se il compilatore è abbastanza intelligente, si ricorderà che il programma originale non richiede l'ordinamento delle y->x, pertanto, questa barriera non è effettivamente necessaria. Ma diciamo che il compilatore non è che intelligente.)


Roach Motel modello -

Il punto di JMM è di stabilire alcuni ordini (parziali) tra le istruzioni su diversi thread, in modo che gli effetti di legge/scrive possono essere definiti. Nel seguente esempio, l'ordine

thread 1    thread 2 

    a1     a2 
    | 
}b1  ----->  b2{ 
         | 
    c1     c2 

una sincronizzazione b1->b2 è stabilito, che potrebbe essere volatile store -> volatile load, o monitor exit -> monitor enter. Questo collega a1->b1->b2->c2 in succede-prima di ordine.

Dal momento che abbiamo bisogno di garantire l'ordinamento delle a1->c2, a1 non deve essere riordinati con b1, e c2 non deve essere prenotato con b2; cioè, uno scarafaggio non può "check out".

D'altra parte, JMM vuole essere il più debole possibile; non dice nulla sugli effetti tra c1 e a2,b2,c2; pertanto, c1 può essere riordinato liberamente con b1.Allo stesso modo, a2 può essere riordinato con b2. Cioè, uno scarafaggio può "fare il check-in".

+0

Anche se "il compilatore è abbastanza intelligente", secondo la mia comprensione, il compilatore ha ancora bisogno per inserire un Store Store nel tuo esempio, perché dovrebbe impedire al processore di riordinare tra istruzioni che precedono l'archivio volatile e lo stesso archivio volatile in modo da imporre la semantica di un archivio volatile. – user2351818

+0

Grazie @ bayou.io per la tua spiegazione dettagliata! La mia comprensione è che, per riassumere, per le letture e le scritture che precedono MonitorEnter o che seguono MonitorExit, esse * possono * essere spostate (riordinate) nella sezione critica durante la compilazione (compilazione JIT). Tuttavia, una volta completata la compilazione , le letture/scritture spostate non possono essere spostate dal processore, a causa delle barriere di memoria inserite dal compilatore che saranno considerate dal processore, vero? – user2351818

+0

Supponiamo che il programma originale sia 'normale archivio A; negozio volatile B'. La semantica di JMM è che, dopo che un altro thread vede l'effetto di B, dovrebbe anche vedere l'effetto di A. Ora, è compito di JVM implementare quella semantica su una particolare architettura della CPU. Una CPU può eseguire scritture fuori ordine per impostazione predefinita; ma supporterà anche un'istruzione di barriera per disabilitarlo. Quindi su quella CPU, JVM prima manterrà l'ordine di A e B, cioè, nessun riordino da JVM; quindi JVM inserirà StoreStore tra A e B, ovvero senza riordino da parte della CPU. – ZhongYu

Problemi correlati