Le code suivant montre comment synchroniser des méthodes de classe spécifiques :
Copiez le code comme suit :
mythread du paquet ;
la classe publique SyncThread étend Thread
{
synchronisation de chaîne statique privée = "" ;
méthode de chaîne privée = "" ;
méthode privée de vide statique (String s)
{
synchronisé (sync)
{
synchronisation = s ;
System.out.println(s);
tandis que (vrai) ;
}
}
méthode vide publique1()
{
méthode("méthode1");
}
public static void staticMethod1()
{
méthode("Méthodestatique1");
}
exécution publique vide()
{
if (methodType.equals("static"))
méthodestatique1();
sinon si (methodType.equals("nonstatic"))
méthode1();
}
public SyncThread (String methodType)
{
this.methodType = methodType;
}
public static void main (String[] args) lève une exception
{
SyncThread sample1 = new SyncThread("nonstatic");
SyncThread sample2 = new SyncThread("statique");
exemple1.start();
exemple2.start();
}
}
Les résultats en cours d'exécution sont les suivants :
Copiez le code comme suit :
méthode1
méthodestatique1
De nombreux lecteurs pourraient être surpris de voir les résultats ci-dessus. Dans le code ci-dessus, les méthodes method1 et staticMethod1 utilisent la variable de chaîne statique sync pour la synchronisation. Une seule de ces deux méthodes peut être exécutée en même temps, et les deux méthodes exécuteront l'instruction de boucle infinie de la ligne 014. Par conséquent, le résultat de sortie ne peut être que l’un des méthodes method1 et staticMethod1. Mais ce programme génère les deux chaînes.
La raison de ce résultat est très simple, nous le saurons en regardant la ligne 012. Il s'avère que la valeur de sync est modifiée dans cette ligne. Ici, je veux parler du type String en Java. Le type String est différent des autres types complexes en Java. Lorsque vous utilisez une variable de type String, tant que vous attribuez une valeur à la variable une fois, Java créera une nouvelle instance du type String. Comme indiqué dans le code suivant :
Copiez le code comme suit :
Chaîne s = "bonjour" ;
System.out.println(s.hashCode());
s = « monde » ;
System.out.println(s.hashCode());
dans le code ci-dessus. Les valeurs hashCode des premiers s et des s réaffectés sont différentes. Puisque la création d'une instance de la classe String ne nécessite pas l'utilisation de new, lors de la synchronisation d'une variable de type String, veillez à ne pas attribuer de valeur à cette variable, sinon la variable ne sera pas synchronisée.
Puisqu'une nouvelle instance de synchronisation a été créée à la ligne 012, en supposant que la méthode1 soit exécutée en premier, lorsque la méthode1 exécute le code de la ligne 013, la valeur de sync n'est plus la valeur d'origine et la méthode1 verrouille toujours la variable de synchronisation la valeur initiale. . À l'heure actuelle, staticMethod1 est exécuté pour synchronisé(sync). La synchronisation à verrouiller dans la méthode staticMethod1 et la synchronisation verrouillée par la méthode method1 ne sont plus les mêmes. Par conséquent, la synchronisation des deux méthodes a été détruite.
La solution au problème ci-dessus est bien entendu de supprimer la ligne 012. Cette ligne est ajoutée à cet exemple juste pour illustrer que lors de l'utilisation de variables de classe pour synchroniser des méthodes, si la valeur de la variable de synchronisation est modifiée dans le bloc synchronisé, la synchronisation entre les méthodes sera détruite. Afin d'éviter complètement cette situation, vous pouvez utiliser le mot-clé final lors de la définition des variables de synchronisation. Par exemple, la ligne 005 du programme ci-dessus peut être modifiée sous la forme suivante :
Copiez le code comme suit :
private final static String sync = "" ;
Après avoir utilisé le mot-clé final, sync ne peut lui attribuer une valeur que lorsqu'elle est définie, et elle ne peut pas être modifiée ultérieurement. Si une valeur est attribuée à sync ailleurs dans le programme, le programme ne sera pas compilé. Dans les outils de développement tels qu'Eclipse, les invites seront affichées directement au mauvais endroit.
Nous pouvons comprendre les blocs synchronisés sous deux angles. Si elles sont comprises du point de vue des méthodes de classe, les méthodes correspondantes peuvent être synchronisées via des variables de classe. Si vous le comprenez du point de vue des variables de classe, vous pouvez utiliser des blocs synchronisés pour garantir qu'une variable de classe n'est accessible que par une seule méthode à la fois. Quel que soit l'angle sous lequel vous le comprenez, leur essence est la même, à savoir utiliser des variables de classe pour obtenir des verrous de synchronisation et réaliser la synchronisation grâce à l'exclusion mutuelle des verrous de synchronisation.
Remarque : lorsque vous utilisez des blocs synchronisés, vous devez savoir que les blocs synchronisés ne peuvent utiliser que des objets comme paramètres. S'il s'agit d'un type simple de variable (comme int, char, boolean, etc.), synchronisé ne peut pas être utilisé pour la synchronisation.