J'ai deux threads Thread1
et Thread2
//Within Thread1
synchronized(obj1)
{
obj1 = null;
}
//Within Thread2
synchronized(obj1)
{
do something
}
Si jvm exécute d'abord thread1 et définit obj1 sur null, alors thread2 verra ce changement immédiatement ou cela prendra du temps et jvm pourra toujours exécuter le bloc thread2 synchronisé puisque obj1 n'est pas encore nul
Cela rompra presque certainement l'abstraction de la synchronisation - je ne serais pas sûr que thread2
verra le changement immédiatement. Vous ne devriez jamais changer la référence de l'objet sur lequel vous synchronisez, et encore moins le définir sur null
, ce qui entraînera une NullPointerException
lors de toute nouvelle tentative de synchronisation sur cet objet.
Permettez-moi tout d’abord de souligner que la modification d’une variable utilisée pour la synchronisation est une très mauvaise chose ™. obj1
devrait être final
et ne jamais être touché s'il est utilisé comme moniteur.
Cela étant dit, revenons à votre question:
Si la machine virtuelle Java exécute pour la première fois Thread1, elle se synchronise sur obj1
, la définit sur null
et le thread se ferme. Le deuxième thread veut se synchroniser sur obj1
, NullPointerException
sera levé. Étant donné que la modification de obj1
a été effectuée dans un bloc synchronisé, il est garanti que Thread2 verra la valeur mise à jour (donc: NullPointerException
est garanti).
Si Thread1 est interrompu après avoir obtenu le verrou sur obj1
mais avant d'effacer la référence, Thread2 se verrouille sur obj1
et attend la fin de Thread1. Il entrera ensuite avec succès dans le moniteur car l'objet précédemment référencé par obj1
existe toujours.
synchronized
se synchronise sur l'objet et non sur la référence. En définissant obj1
(une référence) sur null, thread2 ne peut pas se synchroniser sur l'objet précédemment désigné par obj1
, vous obtiendrez plutôt une NullPointerException
.
Le changement est immédiat. Lorsque le thread 1 "possède" le verrou, il peut changer la valeur de obj1 à volonté. Le thread 2 doit attendre que le thread 1 lâche le verrou. Vous verrez certainement obj1 == null
Une solution rapide consiste à transformer l'objet en un tableau simple de 1 élément et à faire référence au tableau pour la synchronisation, par exemple:
Object [] obj1 = {null};
L'élément peut être null sans impacter l'existence du tableau. Certes, cela brise toujours la "règle" de ne pas utiliser l'objet lui-même en synchronisation, mais à moins que votre code ne complique les choses ailleurs, cette solution rapide devrait fonctionner comme prévu.