J'utilise la classe LazyReference
depuis quelques années (pas régulièrement, bien sûr, mais parfois c'est très utile). La classe peut être vue here. Les crédits vont à Robbie Vanbrabant (auteur de la classe) et Joshua Bloch avec son fameux "Effective Java 2nd edt". (code d'origine).LazyReference avec double-contrôle de verrouillage et manipulation de zéro
La classe fonctionne correctement (dans Java 5+) mais il y a un petit problème potentiel. Si instanceProvider
renvoie null
(bien il ne doit pas selon le contrat Provider.get()
de Guice, mais ...) puis à chaque exécution de la méthode LazyReference.get()
le verrouillage sera tenu et instanceProvider.get
sera appelé encore et encore. Cela ressemble à une bonne punition pour ceux qui brisent les contrats (he-he), mais que se passe-t-il s'il faut vraiment paresseusement initialiser un champ avec la possibilité de définir la valeur null
?
J'ai modifié LazyReference un peu:
public class LazyReference<T> {
private final Object LOCK = new Object();
private volatile T instance;
private volatile boolean isNull;
private final Provider<T> instanceProvider;
private LazyReference(Provider<T> instanceProvider) {
this.instanceProvider = instanceProvider;
}
public T get() {
T result = instance;
if (result == null && !isNull) {
synchronized (LOCK) {
result = instance;
if (result == null && !isNull) {
instance = result = instanceProvider.get();
isNull = (result == null);
}
}
}
return result;
}
}
à mon humble avis, il devrait fonctionner très bien (si vous avez un autre avis s'il vous plaît poster vos commentaires et critiques). Mais je me demande ce qui se passera si je supprime le modificateur volatile
de isNull
booléen (en laissant pour instance
bien sûr)? Cela fonctionnera-t-il toujours correctement?
'l'instance n'a pas besoin d'être volatile' - Bon point! Puisque 'instance' est écrit avant le champ volatil' initialized', il sera visible par tous les autres threads qui lisent 'initialized'. – Idolon