2010-05-07 13 views
64

Dans ArrayBlockingQueue, toutes les méthodes nécessitant le verrouillage le copient dans une variable locale final avant d'appeler lock().Dans ArrayBlockingQueue, pourquoi copier le champ du membre final dans la variable 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(); 
    } 
} 

Y at-il raison de copier this.lock à une variable locale lock lorsque le champ this.lock est final?

De plus, il utilise également une copie locale de E[] avant d'agir sur elle:

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

Y at-il raison de la copie d'un champ final à une variable finale locale?

Répondre

52

C'est une optimisation extrême que Doug Lea, l'auteur de la classe, aime utiliser. Voici un post sur a recent thread sur la liste de diffusion core-libs-dev à propos de ce sujet précis qui répond assez bien à votre question.

du poste:

... La copie à la population locale produit le plus petit bytecode, et pour le code de bas niveau, il est agréable d'écrire du code qui est un peu plus proche de la machine

+11

accent sur « extrême »! Ce n'est pas une bonne pratique de programmation générale que tout le monde devrait imiter. –

+12

FYI aléatoire: dans certains autres cas, lorsque vous voyez ceci, c'est parce que le champ en question est volatile, et la méthode doit s'assurer qu'il y a une seule valeur cohérente ou une référence pour cela. –

+2

Je vais prendre cette optimisation "extrême" dans une classe de base comme celle-ci. –

9

This thread donne quelques réponses. En substance:

  • le compilateur ne peut pas prouver facilement qu'un champ final ne change pas dans une méthode (en raison de la réflexion, etc./sérialisation)
  • la plupart des compilateurs actuels n'essayez pas réellement et aurait donc pour recharger le dernier champ à chaque fois qu'il est utilisé qui pourrait conduire à un manque de cache ou d'un défaut de la page
  • stocker dans une variable locale oblige la machine virtuelle Java pour effectuer une seule charge
+1

Je ne pense pas qu'une variable 'final' doive être rechargée par la JVM. Si vous modifiez une variable 'final' par réflexion, vous perdez la garantie que votre programme fonctionne correctement (ce qui signifie que la nouvelle valeur peut ne pas être prise en compte dans tous les cas). – icza