2010-05-07 8 views
64

En ArrayBlockingQueue, todos los métodos que requieren el bloqueo lo copian en una variable local final antes de llamar al lock().En ArrayBlockingQueue, ¿por qué copiar el campo miembro final en la variable final local?

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(); 
    } 
} 

¿Hay alguna razón para copiar this.lock a una variable local lock cuando el campo es this.lockfinal?

Además, también se utiliza una copia local de E[] antes de actuar sobre ella:

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

¿Hay alguna razón para copiar un campo final a una última variable local?

Respuesta

52

Es una optimización extrema que a Doug Lea, el autor de la clase, le gusta usar. Aquí hay una publicación en a recent thread en la lista de correo core-libs-dev sobre este tema exacto que responde bastante bien a su pregunta.

del poste:

... copia a la población local produce la código de bytes más pequeño, y por código de bajo nivel es agradable escribir código que es un poco más cerca de la máquina

+11

fuerte énfasis en la "extrema"! Esta no es una buena práctica de programación de propósito general que todos deberían emular. –

+12

FYI aleatorio: en otros casos, cuando ve esto hecho, es porque el campo en cuestión es volátil, y el método necesita asegurarse de que tenga un solo valor consistente o referencia para él en todo momento. –

+2

Tomaré esta optimización "extrema" en una clase básica como esta. –

9

This thread da algunas respuestas. En sustancia:

  • el compilador no puede demostrar fácilmente que un campo final no cambia dentro de un método (debido a la reflexión/serialización etc.) compiladores
  • más actuales en realidad no trate y por lo tanto tienen para recargar la cada campo final se utiliza lo que podría conducir a un fallo de caché o un fallo de página
  • almacenarlo en una variable local obliga a la JVM para realizar una sola carga
+1

No creo que la JVM deba volver a cargar una variable 'final'. Si modifica una variable 'final' mediante reflexión, pierde la garantía de que su programa funciona correctamente (lo que significa que el nuevo valor podría no tenerse en cuenta en todos los casos). – icza

Cuestiones relacionadas