2010-05-07 6 views
64

In ArrayBlockingQueue, tutti i metodi che richiedono il blocco lo copiano in una variabile locale final prima di chiamare lock().In ArrayBlockingQueue, perché copiare il campo membro finale nella variabile finale locale?

public boolean offer(E e) { 
    if (e == null) throw new NullPointerException(); 
    final ReentrantLock lock = this.lock; 
    lock.lock(); 
    try { 
     if (count == items.length) 
      return false; 
     else { 
      insert(e); 
      return true; 
     } 
    } finally { 
     lock.unlock(); 
    } 
} 

C'è qualche motivo per copiare this.lock a una variabile locale lock quando il campo è this.lockfinal?

Inoltre, utilizza anche una copia locale di E[] prima di agire su di esso:

private E extract() { 
    final E[] items = this.items; 
    E x = items[takeIndex]; 
    items[takeIndex] = null; 
    takeIndex = inc(takeIndex); 
    --count; 
    notFull.signal(); 
    return x; 
} 

C'è qualche motivo per la copia di un campo finale a una variabile finale locale?

risposta

52

È un'ottimizzazione estrema che piace a Doug Lea, l'autore della classe. Ecco un post su a recent thread sulla mailing list core-libs-dev su questo argomento esatto che risponde alla tua domanda abbastanza bene.

da posta:

... la copia per i locali produce il più piccolo bytecode, e per il codice a basso livello è bello scrivere codice che è un po 'più vicino alla macchina

+11

forte accento sulla "estreme"! Questa non è una buona pratica di programmazione generale che tutti dovrebbero emulare. –

+12

FYI casuale: in alcuni altri casi quando si vede questo fatto, è perché il campo in questione è volatile, e il metodo deve assicurarsi che abbia un singolo valore coerente o riferimento per tutto questo. –

+2

Prenderò questa ottimizzazione "estrema" in una classe di base come questa. –

9

This thread fornisce alcune risposte. In sostanza:

  • il compilatore non può facilmente dimostrare che un campo finale non cambia all'interno di un metodo (a causa di riflessione/serializzazione ecc) compilatori
  • più attuali realtà non provate e avrebbe perciò per ricaricare l'ogni campo finale è usato che potrebbe portare ad una miss cache o un errore di pagina
  • memorizzandolo in una variabile locale costringe JVM per eseguire un solo carico
+1

Non penso che una variabile 'finale' debba essere ricaricata dalla JVM. Se modifichi una variabile 'finale' tramite riflessione, perdi la garanzia che il tuo programma funzioni correttamente (il che significa che il nuovo valore potrebbe non essere preso in considerazione in tutti i casi). – icza