Findbug m'a dit que j'utilisais une initialisation paresseuse incorrecte.
public static Object getInstance() {
if (instance != null) {
return instance;
}
instance = new Object();
return instance;
}
Je ne vois rien de mal ici. Est-ce un mauvais comportement de findbug ou j'ai raté quelque chose?
Findbug fait référence à un problème de thread potentiel. Dans un environnement multi-thread, il serait possible que votre singleton soit créé plus d'une fois avec votre code actuel.
Il y a beaucoup de lecture ici , mais cela aidera à expliquer.
La condition de course est ici sur le if check
. Au premier appel, un thread entrera dans le if check
, et créera l'instance et l'affectera à 'instance'. Mais il est possible qu'un autre thread devienne actif entre le if check
et la création/affectation de l'instance. Ce fil pourrait également passer le if check
car l'affectation n'a pas encore eu lieu. Par conséquent, deux instances (ou plus, si davantage de threads entraient) seraient créées et vos threads auraient des références à différents objets.
Votre code est légèrement plus complexe que nécessaire, ce qui pourrait expliquer pourquoi il est confus.
Edit: C'est certainement le problème de filetage comme les autres l'ont signalé, mais j'ai pensé publier la mise en œuvre de la vérification du double verrouillage ici pour référence ci-dessous:
private static final Object lock = new Object();
private static volatile Object instance; // must be declared volatile
public static Object getInstance() {
if (instance == null) { // avoid sync penalty if we can
synchronized (lock) { // declare a private static Object to use for mutex
if (instance == null) { // have to do this inside the sync
instance = new Object();
}
}
}
return instance;
}
NOTE : La solution de vérification de double verrouillage de JohnKlehm est meilleure. Laissant cette réponse ici pour des raisons historiques.
Cela devrait être
public synchronized static Object getInstance() {
if (instance == null) {
instance = new Object();
}
return instance;
}
Vous devez verrouiller l'instanciation pour que cela soit correct
LI: initialisation paresseuse incorrecte du champ statique (LI_LAZY_INIT_STATIC)
Cette méthode contient une initialisation paresseuse non synchronisée d'un champ statique non volatile. Étant donné que le compilateur ou le processeur peut réorganiser les instructions, les threads ne sont pas garantis de voir un objet complètement initialisé, si la méthode peut être appelée par plusieurs threads. Vous pouvez rendre le champ volatile pour corriger le problème. Pour plus d'informations, consultez le site Web Java Memory Model).
Vous avez manqué un problème de multi-threading,
private static Object instance;
public static synchronized Object getInstance() {
return (instance != null ? instance : (instance = new Object()));
}
Merci à John Klehm pour l'échantillon publié
peut également essayer d'affecter directement une instance d'objet dans un bloc synchronisé
synchronized (MyCurrentClass.myLock=new Object())
c'est à dire.
private static volatile Object myLock = new Object();
public static Object getInstance() {
if (instance == null) { // avoid sync penalty if we can
synchronized (MyCurrentClass.myLock**=new Object()**) { // declare a private static Object to use for mutex
if (instance == null) { // have to do this inside the sync
instance = new Object();
}
}
}
return instance;
}
votre objet statique n'est pas synchronisé. De plus, votre méthode n'est pas une initialisation paresseuse. Normalement, vous conservez une carte d'objet et vous initialisez celle souhaitée à la demande. Donc, vous ne les initialisez pas tous au début plutôt que de les appeler quand cela est nécessaire (appelé).
Depuis 1.5: l'instance doit être volatile et vous devez intégrer une variable tmp pour éviter d'utiliser une instance créée mais son initialisation n'est pas encore terminée.
private static volatile Object myLock = new Object();
private static volatile Object instance;
public static Object getInstance() {
if (instance == null) {
Object tmpObj;
synchronized (myLock) {
tmpObj = instance;
if (tmpObj == null) {
tmpObj = new Object();
}
}
instance = tmpObj;
}
return instance;
}