2013-06-18 16 views
7

Ciao di seguito è riportato lo snippet della seconda edizione di Java efficace. Qui l'autore sostiene che il seguente codice è il 25% più veloce di quello in cui non si usa la variabile risultato. In base al libro "Ciò che fa questa variabile è assicurarsi che il campo venga letto solo una volta nel caso comune in cui è già stato inizializzato." . Non riesco a capire perché questo codice sarebbe veloce dopo che il valore è stato inizializzato con il confronto di se non si utilizza il risultato della variabile Locale. In entrambi i casi si avrà una sola lettura volatile dopo l'inizializzazione, indipendentemente dal fatto che si usi il risultato della variabile locale o meno.Perché il doppio controllo del blocco è più rapido del 25% in Joshua Bloch Esempio Java efficace

// Double-check idiom for lazy initialization of instance fields 
private volatile FieldType field; 

FieldType getField() { 
    FieldType result = field; 
    if (result == null) { // First check (no locking) 
     synchronized(this) { 
      result = field; 
      if (result == null) // Second check (with locking) 
       field = result = computeFieldValue(); 
     } 
    } 
    return result; 
} 
+1

Uhm, questa è la prima edizione? Il blocco a doppio controllo è stato scoraggiato da alcuni anni – fge

+0

E il motivo è: http://stackoverflow.com/questions/4926681/why-is-double-checked-locking-broken-in-java?rq=1 – Lenymm

+4

@fge : Non proprio. Dal momento che Java 5, in realtà è un modello OK: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html –

risposta

6

volta field è stata inizializzata, il codice può essere:

if (field == null) {...} 
return field; 

o:

result = field; 
if (result == null) {...} 
return result; 

Nel primo caso si legge la variabile volatile, per due volte, mentre nel secondo solamente leggilo una volta Sebbene le letture volatili siano molto veloci, possono essere un po 'più lente della lettura da una variabile locale (non so se è del 25%).

Note:

  • volatili legge sono a buon mercato come normale legge sui recenti processori (almeno x86)/JVM, vale a dire non v'è alcuna differenza.
  • tuttavia il compilatore può ottimizzare meglio un codice senza volatile in modo da ottenere l'efficienza da un codice compilato migliore.
  • Il 25% di pochi nanosecondi non è ancora molto.
  • si tratta di un linguaggio standard che si possono trovare in molte classi del pacchetto java.util.concurrent - vedi ad esempio this method in ThreadPoolExecutor (ci sono molti di loro)
+0

ok quindi significa che "campo di ritorno" costituisce anche una lettura volatile (il campo fornito è volatile) – veritas

+0

@veritas Sì, se si esamina il codice byte si vedrà che viene caricato prima di essere restituito. – assylias

+0

ok grazie mille @assylias – veritas

0

Senza usare una variabile locale, nella maggior parte dei invocazioni abbiamo efficacemente

if(field!=null) // true 
    return field; 

quindi ci sono due letture volatili, che è più lento di una lettura volatile.

In realtà JVM può unire le due letture volatili in una lettura volatile e comunque conforme a JMM. Ma ci aspettiamo che JVM esegua una lettura volatile in buona fede ogni volta che gli viene detto, per non essere uno stupido e cercare di ottimizzare ogni lettura volatile. Considerare questo codice

volatile boolean ready; 

do{}while(!ready); // busy wait 

ci aspettiamo che JVM carichi realmente la variabile ripetutamente.

Problemi correlati