2013-05-20 6 views
10

dire che hai questo codice:In un blocco sincronizzato Java, le scritture sono visibili su tutti i campi o solo sulla variabile sincronizzata?

private String cachedToken; 
private final Object lockObject = new Object(); 

.... 


retrieveToken(){ 
synchronized(lockObject){ 
    if (cachedToken == null){ 
    cachedToken = goGetNewToken(); 
    } 
    return cachedToken; 
} 
} 

disposta la scrittura per cachedToken essere visibile a tutte le discussioni che si sono bloccati su lockObject?

+0

Sì, questo è il punto ... Ma la scrittura potrebbe accadere alla cache della CPU l1 o l2 e non essere scaricata nella memoria principale prima che un altro thread ottenga il blocco. –

+0

Non è vero. Se un altro thread si blocca su 'lockObject' dopo che un altro thread ha scritto e poi esce, il thread in entrata vedrà la scrittura. –

+0

Nota: le scritture sulla "variabile sincronizzata" sono spesso * errate *. Il codice è sincronizzato su un oggetto, non su una variabile. Se la variabile viene modificata midstream per fare riferimento a un oggetto diverso, più blocchi sincronizzati sull'oggetto a cui fa riferimento tale variabile potrebbero essere eseguiti contemporaneamente. –

risposta

7

Sì. La sincronizzazione su lockObject stabilisce un evento Happens Before Relationship (ovvero imposta una barriera di memoria). Ciò significa che tutti i thread che successivamente ottengono il blocco vedranno tutte le modifiche avvenute mentre il blocco è stato trattenuto in precedenza.

Per quello che vale, tuttavia, l'implementazione dell'inizializzazione pigra è difettosa. Questo è il modo corretto:

private volatile String cachedToken; 

retrieveToken() { 
    if (cachedToken == null) { 
     synchronized(lockObject) { 
      if (cachedToken == null) { 
       cachedToken = goGetNewToken(); 
      } 
     } 
    } 
    return cachedToken 
} 

In questo modo è sufficiente per ottenere il blocco di una piccola manciata di volte in cui le discussioni iniziare prima che ne facciano richiesta. Successivamente, il cachedToken non sarà nullo e non sarà necessario sincronizzarsi.

+0

E quella barriera di memoria includerà qualsiasi campo toccato, non solo l'oggetto su cui sono sincronizzato? –

+0

@ Tom McIntyre Il tuo modo di fare è in realtà pericoloso. Guarda questo: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – Mik378

+1

sì, altrimenti la concorrenza a stato condiviso sarebbe ancora più difficile di quanto non sia già! –

5

Naturalmente, synchronize garantire due cose:

  • atomicità
  • barriera di memoria (ciò che vi aspettate nel tuo caso) sull'intero oggetto

considerando che, per esempio, volatile garantire barriera di memoria ma non gestisce l'atomicità.

+0

a prescindere da letture e scritture a lungo o doppio, in cui la volatilità rende l'atomicità. –

+0

@ Tom McIntyre Sì, ma non è dovuto alla parola chiave 'volatile' stessa. – Mik378

+0

come intendi "non dovuto alla stessa parola chiave volatile"? –

Problemi correlati