Les verrous de classe et les verrous d’objets entreront-ils en conflit ? Les verrous d'objet et les verrous privés seront-ils en conflit ? Illustration à travers des exemples.
1. Accords pertinents
Afin de clarifier la description suivante, nous établissons d'abord les conventions suivantes sur les définitions pertinentes des verrous impliqués dans cet article :
1. Verrouillage de classe : ajoutez des verrous statiques et synchronisés aux méthodes du code ou aux segments de code synchronisés (xxx.class), tels que increament() ci-dessous ;
2. Verrouillage d'objet : ajoutez un verrou synchronisé à la méthode dans le code, ou un segment de code synchronisé (ce), tel que synOnMethod() et synInMethod() ci-dessous ;
3. Verrouillage privé : déclarez une propriété privée telle que le verrouillage d'objet privé à l'intérieur de la classe et synchronisez (verrouillez) le segment de code qui doit être verrouillé, tel que synMethodWithObj() ci-dessous.
2. Tester le code
1. Écrivez une classe de démarrage ObjectLock
Copiez le code comme suit :
classe publique ObjectLock {
public static void main (String[] arguments) {
System.out.println("heure de début = " + System.currentTimeMillis()+"ms");
Test LockTestClass = new LockTestClass();
pour (int je = 0; je < 3; i++) {
Fil de discussion = nouveau ObjThread(test, i);
thread.start();
}
}
}
2. Écrivez une classe de thread ObjThread pour démarrer la méthode de synchronisation (notez que sa méthode d'exécution peut être ajustée pour différents tests)
Copiez le code comme suit :
la classe publique ObjThread étend Thread {
Verrouillage LockTestClass ;
int je = 0;
public ObjThread (verrouillage LockTestClass, int i) {
this.lock = verrouiller;
ceci.i = je;
}
public void run() {
//Méthode sans verrouillage
//lock.noSynMethod(this.getId(),this);
//Méthode de verrouillage d'objet 1, utilisant synInMethod synchronisé
lock.synInMethod();
// Méthode de verrouillage d'objet 2, utilisant la méthode synchronisée (this)
//lock.synOnMethod();
//Méthode de verrouillage privé, utilisant la méthode synchronisée (objet)
//lock.synMethodWithObj();
//Méthode de verrouillage de classe, utilisant la méthode d'incrémentation synchronisée statique
LockTestClass.increment();
}
}
3. Écrivez une autre classe de test de verrouillage LockTestClass, comprenant diverses méthodes de verrouillage
Copiez le code comme suit :
classe publique LockTestClass {
//Utilisé pour le comptage des verrous de classe
int statique privé i = 0 ;
//Serrure privée
objet privé objet = nouvel objet ();
/**
* <p>
* Méthode sans verrouillage
*
* @param ID de fil
* Fil de discussion @param
*/
public void noSynMethod (ID de fil long, fil ObjThread) {
System.out.println("nosyn : la classe obj est " + thread + ", threadId est "
+ ID de fil);
}
/**
* Méthode de verrouillage d'objet 1
*/
public synchronisé void synOnMethod() {
System.out.println("synOnMethod commence" + ", time = "
+ System.currentTimeMillis() + "ms");
essayer {
Fil.sommeil (2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synOnMethod se termine");
}
/**
* Méthode de verrouillage d'objet 2, utilisez synchronisé (ceci) pour verrouiller
*/
public void synInMethod() {
synchronisé (ce) {
System.out.println("synInMethod commence" + ", time = "
+ System.currentTimeMillis() + "ms");
essayer {
Fil.sommeil (2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synInMethod se termine");
}
}
/**
* Méthode de verrouillage d'objet 3
*/
public void synMethodWithObj() {
synchronisé (objet) {
System.out.println("synMethodWithObj commence" + ", time = "
+ System.currentTimeMillis() + "ms");
essayer {
Fil.sommeil (2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synMethodWithObj se termine");
}
}
/**
* Verrouillage de classe
*/
public static synchronisé void increament() {
System.out.println("class synchronisée. i = " + i + ", time = "
+ System.currentTimeMillis() + "ms");
je++;
essayer {
Fil.sommeil (2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("fins synchronisées de la classe.");
}
}
3. Résultats des tests
1. Pour tester les verrous de classe et les verrous d'objet, modifiez la méthode run d'ObjectThread comme suit :
Copiez le code comme suit :
public void run() {
//Méthode sans verrouillage
//lock.noSynMethod(this.getId(),this);
//Méthode de verrouillage d'objet 1, utilisant synInMethod synchronisé
lock.synInMethod();
// Méthode de verrouillage d'objet 2, utilisant la méthode synchronisée (this)
//lock.synOnMethod();
//Méthode de verrouillage privé, utilisant la méthode synchronisée (objet)
//lock.synMethodWithObj();
//Méthode de verrouillage de classe, utilisant la méthode d'incrémentation synchronisée statique
LockTestClass.increament();
}
Sortie terminale :
Copiez le code comme suit :
heure de début = 1413101360231ms
synInMethod commence, temps = 1413101360233 ms
synInMethod se termine
classe synchronisée i = 0, temps = 1413101362233ms.
synInMethod commence, temps = 1413101362233 ms
fin de classe synchronisée.
synInMethod se termine
classe synchronisée i = 1, temps = 1413101364233ms.
synInMethod commence, temps = 1413101364233 ms
fin de classe synchronisée.
synInMethod se termine
classe synchronisée i = 2, temps = 1413101366234ms.
fin de classe synchronisée.
Vous pouvez voir que la méthode de verrouillage d'objet (synInMothod) est 2 secondes plus rapide que la méthode de verrouillage de classe (increament) lors de son premier démarrage, car lorsque synInMehtod est exécuté, elle dort pendant 2 secondes puis exécute increament, et ces deux-là. les méthodes partagent le même thread. Ce sera donc 2 secondes plus lent. Si increament est placé devant synInMethod lors de l'exécution, alors increament sera 2 secondes plus rapide lorsqu'il est démarré pour la première fois.
Lorsque la méthode de verrouillage de classe est démarrée, la méthode de verrouillage d'objet d'un autre thread est également démarrée presque en même temps, indiquant que les deux n'utilisent pas le même verrou et qu'il n'y aura pas de concurrence.
Conclusion : les verrous de classe et les verrous d'objet ne seront pas en concurrence et leurs méthodes de verrouillage ne s'influenceront pas mutuellement.
2. Verrous privés et verrous d'objet, la méthode run d'ObjectThread est modifiée comme suit :
Copiez le code comme suit :
public void run() {
//Méthode sans verrouillage
//lock.noSynMethod(this.getId(),this);
//Méthode de verrouillage d'objet 1, utilisant synInMethod synchronisé
lock.synInMethod();
// Méthode de verrouillage d'objet 2, utilisant la méthode synchronisée (this)
//lock.synOnMethod();
//Méthode de verrouillage privé, utilisant la méthode synchronisée (objet)
lock.synMethodWithObj();
//Méthode de verrouillage de classe, utilisant la méthode d'incrémentation synchronisée statique
//LockTestClass.increament();
}
Sortie terminale :
Copiez le code comme suit :
heure de début = 1413121912406ms
synInMethod commence, temps = 1413121912407 ms.
synInMethod se termine.
synMethodWithObj commence, temps = 1413121914407 ms
synInMethod commence, temps = 1413121914407 ms.
synInMethod se termine.
synMethodWithObj se termine
synInMethod commence, temps = 1413121916407 ms.
synMethodWithObj commence, temps = 1413121916407 ms
synInMethod se termine.
synMethodWithObj se termine
synMethodWithObj commence, temps = 1413121918407 ms
synMethodWithObj se termine
Très similaire aux verrous de classe et aux verrous d'objet.
Conclusion : les verrous privés et les verrous d'objet ne seront pas en concurrence et leurs méthodes de verrouillage ne s'influenceront pas mutuellement.
3.Synchronized est directement ajouté à la méthode et synchronisé (this), et la méthode d'exécution d'ObjectThread est modifiée comme suit :
Copiez le code comme suit :
public void run() {
//Méthode sans verrouillage
//lock.noSynMethod(this.getId(),this);
//Méthode de verrouillage d'objet 1, utilisant synInMethod synchronisé
lock.synInMethod();
// Méthode de verrouillage d'objet 2, utilisant la méthode synchronisée (this)
lock.synOnMethod();
//Méthode de verrouillage privé, utilisant la méthode synchronisée (objet)
//lock.synMethodWithObj();
//Méthode de verrouillage de classe, utilisant la méthode d'incrémentation synchronisée statique
//LockTestClass.increament();
}
Sortie terminale :
Copiez le code comme suit :
heure de début = 1413102913278ms
synInMethod commence, temps = 1413102913279ms
synInMethod se termine
synInMethod commence, temps = 1413102915279ms
synInMethod se termine
synOnMethod commence, temps = 1413102917279ms
synOnMethod se termine
synInMethod commence, temps = 1413102919279ms
synInMethod se termine
synOnMethod commence, temps = 1413102921279ms
synOnMethod se termine
synOnMethod commence, temps = 1413102923279 ms
synOnMethod se termine
Comme vous pouvez le voir, les deux sorties strictement en série (bien sûr, le fait que synInMethod ou synOnMethod soit exécuté en premier lors de la nouvelle exécution n'est pas déterminé, selon qui obtient le verrou).
Conclusion : synchronisé directement ajouté à la méthode et synchronisé(ce) verrouillent tous deux l'objet courant. Les deux méthodes de verrouillage sont dans une relation compétitive, et une seule méthode peut être exécutée en même temps.