La concurrence multithread peut être obtenue en JAVA via l'instruction synchronisée. À l’aide de blocs de code synchronisés, la JVM garantit qu’un seul thread peut détenir le verrou sur un certain objet en même temps. Le mécanisme de verrouillage permet à plusieurs threads d'accéder en toute sécurité aux ressources critiques.
Le code de synchronisation s'écrit comme suit :
Codage 1 :
Object obj = new Object(); ... synchronisé(obj) { //TODO : Accéder aux ressources critiques} Le multi-threading de JAVA est toujours plein de pièges Si nous utilisons Boolean comme objet synchronisé, les deux situations suivantes peuvent se produire :
1. On pense qu’un objet est verrouillé, mais différents objets sont en réalité synchronisés.
Code 2 :
private volatile Boolean isTrue = false; publich void aMethod() { ... synchronisé(isTrue) { isTrue = !isTrue; //TODO : accéder aux ressources critiques isTrue = !isTrue; À première vue, il n'y a rien de mal avec le code ci-dessus. En raison de l'utilisation de synchronisé(isTrue), un seul thread peut accéder aux ressources critiques en même temps, mais ce n'est pas le cas. Car les deux constantes faux et vrai correspondent à deux objets différents. Lorsque isTrue change, il est probable que différents threads synchronisent différents objets. La boxe automatique de JAVA changera false en Boolean.FALSE et true en Boolean.TRUE (cela montre également que si false est remplacé par Boolean.FALSE, le résultat sera le même). Écrivez le code de test pour l'une des situations ci-dessus comme suit :
Code 3 :
public class BooleanTest { private volatile Boolean isTrue = Boolean.FALSE; //C'est la même chose que false ici public void aMethod() { for(int i=0;i<10;i++) { Thread t = new Thread() { public void run() { synchronisé(isTrue) { isTrue = !isTrue; System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue); try{ Double ran = 1000 * Math.random(); Thread.sleep(ran.intValue()); }catch(InterruptedException e) {} if(!isTrue) System.out.println( Thread.currentThread().getName() + " - Oh, non !"); isTrue = !isTrue } } }; t.start(); } } public static void main(String... args) { BooleanTest bt = new BooleanTest(); Lorsque vous exécutez le code ci-dessus, vous verrez « -Oh, non ! » de temps en temps, indiquant que différents threads entrent dans le bloc de code synchronisé en même temps.
2. On pense que différents objets sont synchronisés, mais il s'agit en réalité d'un seul objet.
Parfois, nous pouvons souhaiter synchroniser plusieurs objets. Si un booléen est utilisé comme objet synchronisé, il est probable que deux blocs de synchronisation qui ne devraient avoir aucune relation utilisent le même verrou d'objet. Les exemples sont les suivants :
Code 4 :
private volatile Boolean aBoolean = Boolean.FALSE; private volatile Boolean anotherBoolean = false; public void aMethod() { ... synchronisé (aBoolean) { //TODO : accéder à la ressource critique 1 } ... } public void anotherMethod() { . .. synchronisé(anotherBoolean) { //TODO : accéder à la ressource critique 2 } ... } Supposons qu’à l’origine, aMethod et anotherMethod seront appelés par deux ensembles de threads non liés. Cependant, puisque Boolean.FALSE et false pointent vers le même objet, l'accès à la ressource critique 2 peut être bloqué par la ressource critique 1 (et vice versa).
Les deux situations ci-dessus indiquent que lors de l'utilisation de blocs synchronisés, essayez de ne pas utiliser d'objets booléens comme objets synchronisés, sinon des problèmes inattendus pourraient survenir ou des pièges pourraient survenir lors de futures modifications du code.
On voit également que toute synchronisation de constantes est risquée. Si vous devez synchroniser Boolean, vous devez utiliser l'opérateur new pour créer un objet booléen.