Dans ce chapitre, nous présenterons des mots clés synchronisés. Le contenu impliqué comprend:
1. Principe synchronisé
2. Règles de base synchronisées
3. Méthode synchronisée et bloc de code synchronisé
4. Lock d'instance et verrouillage global
1. Principe synchronisé
En Java, chaque objet a et n'a qu'un seul verrou de synchronisation. Cela signifie également que le verrouillage de synchronisation existe sur l'objet.
Lorsque nous appelons la méthode synchronisée d'un objet, nous acquérons le verrou de synchronisation de l'objet. Par exemple, Synchronized (OBJ) acquiert le verrou de synchronisation de l'objet "OBJ".
L'accès aux verrous de synchronisation par différents threads s'exclut mutuellement. En d'autres termes, à un certain moment, le verrou de synchronisation de l'objet ne peut être obtenu que par un seul thread! Grâce à des verrous de synchronisation, nous pouvons obtenir un accès mutuellement exclusif aux "objets / méthodes" dans plusieurs threads. Par exemple, il y a maintenant deux threads A et Thread B, qui accèdent tous deux au "Lock synchrone de l'objet OBJ". Supposons qu'à un moment donné, le thread A acquiert le "verrouillage de synchronisation de l'OBJ" et effectue certaines opérations; B ne peut obtenir que le "verrou de synchronisation de l'OBJ" jusqu'à ce que le thread A libère le "verrou synchrone de cet objet" et ne peut s'exécuter.
2. Règles de base synchronisées
Nous résumons les règles de base de la synchronisation dans les 3 suivantes et les illustrons à travers des exemples.
Article 1: Lorsqu'un thread accède à la "méthode synchronisée" ou "bloc de code synchronisé" de "un certain objet", d'autres threads seront bloqués de l'accès à la "méthode synchronisée" ou "bloc de code synchronisé" de "l'objet".
Article 2: Lorsqu'un thread accède à la "méthode synchronisée" ou au "bloc de code synchronisé" de "un certain objet", d'autres threads peuvent toujours accéder au bloc de code asynchronisé de "cet objet".
Article 3: Lorsqu'un thread accède à la "méthode synchronisée" ou au "bloc de code synchronisé" de "un certain objet", d'autres threads seront empêchés d'accéder à d'autres "méthodes synchronisées" ou "bloc de code synchronisé" de "l'objet".
Article 1
Lorsqu'un thread accède à la "méthode synchronisée" ou "bloc de code synchronisé" de "un certain objet", d'autres threads seront bloqués de l'accès à la "méthode synchronisée" ou "bloc de code synchronisé" de "l'objet".
Vous trouverez ci-dessous le programme de démonstration correspondant au "bloc de code synchronisé".
La copie de code est la suivante:
class Myrunable implémente runnable {
@Outrepasser
public void run () {
synchronisé (this) {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + "Loop" + i);
}
} catch (InterruptedException ie) {
}
}
}
}
classe publique Demo1_1 {
public static void main (String [] args) {
Runnable Demo = new Myrunable ();
Thread t1 = nouveau thread (démo, "t1");
Thread t2 = nouveau thread (démo, "t2");
t1.start ();
T2.Start ();
}
}
Résultats en cours:
La copie de code est la suivante:
Boucle T1 0
Boucle T1 1
Boucle T1 2
Boucle T1 3
Boucle T1 4
Boucle T2 0
Boucle T2 1
Boucle T2 2
Boucle T2 3
Boucle T2 4
Description des résultats:
Il existe un "bloc de code synchronisé (ce)" dans la méthode Run (), et T1 et T2 sont des threads créés en fonction de l'objet exécutable "démo". Cela signifie que nous pouvons considérer cela dans Synchronisé (ceci) comme "objet de démo exécutable"; donc, les threads T1 et T2 partagent "Lock synchrone de l'objet de démonstration". Par conséquent, lorsqu'un thread est en cours d'exécution, un autre thread doit attendre que le "thread en cours d'exécution" libère le "verrouillage de synchronisation de démo" avant de pouvoir s'exécuter.
Si vous confirmez, vous avez compris ce problème. Ensuite, nous modifions le code ci-dessus, puis l'exécutons pour voir comment se trouve le résultat et voyons si vous serez confus. Le code source modifié est le suivant:
La copie de code est la suivante:
classe Mythread étend Thread {
public mythread (nom de chaîne) {
super (nom);
}
@Outrepasser
public void run () {
synchronisé (this) {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + "Loop" + i);
}
} catch (InterruptedException ie) {
}
}
}
}
classe publique Demo1_2 {
public static void main (String [] args) {
Thread t1 = new mythread ("t1");
Thread t2 = new mythread ("t2");
t1.start ();
T2.Start ();
}
}
Description du code:
En comparant Demo1_2 et Demo1_1, nous avons constaté que la classe MyThread dans Demo1_2 est directement héritée de Thread, et T1 et T2 sont tous deux des threads enfants Mythread.
Heureusement, la méthode "run () de Demo1_2" également appelé synchronisée (ceci), tout comme la méthode "run () de Demo1_1" également appelé synchronisée (ceci)!
Ainsi, le processus d'exécution de Demo1_2 est-il le même que Demo1_1?
Résultats en cours:
La copie de code est la suivante:
Boucle T1 0
Boucle T2 0
Boucle T1 1
Boucle T2 1
Boucle T1 2
Boucle T2 2
Boucle T1 3
Boucle T2 3
Boucle T1 4
Boucle T2 4
Description des résultats:
Si ce résultat ne vous surprend pas du tout, alors je crois que vous avez une compréhension plus profonde de la synchronisation et de cela. Sinon, veuillez continuer à lire l'analyse ici.
Ceci en synchronisé (ceci) fait référence à "l'objet de classe actuel", c'est-à-dire que l'objet actuel correspondant à la classe où se trouve synchronisé (this). Son objectif est d'obtenir le "verrouillage synchrone de l'objet actuel".
Pour Demo1_2, ceci en synchronisé (ceci) représente l'objet Mythread, tandis que T1 et T2 sont deux objets Mythread différents. Pour la paire Demo1_1, ceci en synchronisé (this) représente l'objet myrunable;
Article 2
Lorsqu'un thread accède à la "méthode synchronisée" ou au "bloc de code synchronisé" de "un certain objet", d'autres threads peuvent toujours accéder au bloc de code asynchronisé de "cet objet".
Vous trouverez ci-dessous le programme de démonstration correspondant au "bloc de code synchronisé".
La copie de code est la suivante:
classe Count {
// Méthode contenant un bloc de synchronisation synchronisé
public void synmethod () {
synchronisé (this) {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "SynMethod Loop" + i);
}
} catch (InterruptedException ie) {
}
}
}
// méthode asynchrone
public vide nonynmethod () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + "LOOP NonsynMethod" + i);
}
} catch (InterruptedException ie) {
}
}
}
classe publique Demo2 {
public static void main (String [] args) {
Count Count final = new Count ();
// Créer un nouveau T1, T1 appellera la méthode SynMethod () de l'objet "Count Object"
Thread t1 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
count.SynMethod ();
}
}, "t1");
// Créer un nouveau T2, T2 appellera la méthode non synto-syntadéhod () de l'objet "Count Object"
Thread t2 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
count.nonsynmethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
Résultats en cours:
La copie de code est la suivante:
T1 Synmethod Loop 0
T2 Boucle non symétrique 0
T1 Synmethod Loop 1
T2 Boucle non syntolie 1
T1 Synmethod Loop 2
T2 Boucle non symétrique 2
T1 Synmethod Loop 3
T2 Boucle non symétrique 3
T1 Synmethod Loop 4
T2 Boucle non syntolie 4
Description des résultats:
Deux nouveaux fils d'enfants T1 et T2 sont créés dans le thread principal. T1 appellera la méthode SynMethod () de l'objet Count, qui contient des blocs de synchronisation; Lorsque T1 est en cours d'exécution, bien que synchronisé (ceci) est appelé pour obtenir le «verrou de synchronisation du nombre»;
Article 3
Lorsqu'un thread accède à la "méthode synchronisée" ou "bloc de code synchronisé" de "un certain objet", d'autres threads accès à d'autres "méthodes synchronisées" ou "bloc de code synchronisé" de "l'objet" sera bloqué.
Nous allons également modifier le corps de la méthode non synto-syntadéhod () dans l'exemple ci-dessus avec synchronisé (ceci). Le code source modifié est le suivant:
La copie de code est la suivante:
classe Count {
// Méthode contenant un bloc de synchronisation synchronisé
public void synmethod () {
synchronisé (this) {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "SynMethod Loop" + i);
}
} catch (InterruptedException ie) {
}
}
}
// contient également une méthode de bloc de synchronisation synchronisée
public vide nonynmethod () {
synchronisé (this) {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + "LOOP NonsynMethod" + i);
}
} catch (InterruptedException ie) {
}
}
}
}
classe publique Demo3 {
public static void main (String [] args) {
Count Count final = new Count ();
// Créer un nouveau T1, T1 appellera la méthode SynMethod () de l'objet "Count Object"
Thread t1 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
count.SynMethod ();
}
}, "t1");
// Créer un nouveau T2, T2 appellera la méthode non synto-syntadéhod () de l'objet "Count Object"
Thread t2 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
count.nonsynmethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
(Une fois) Résultat d'exécution:
La copie de code est la suivante:
synmethod (): 11
synblock (): 3
4. Lock d'instance et verrouillage global
Verrouillage de l'instance - verrouillé sur un objet d'instance. Si la classe est un singleton, le verrou a également le concept de verrouillage mondial.
Le mot-clé synchronisé correspond au verrouillage de l'instance.
Global Lock - Ce verrou est ciblé sur une classe.
Le verrou global correspond à statique synchronisée (ou verrouillée sur la classe ou l'objet Classloader de cette classe).
Il y a un exemple très vivant de "Lock d'instance" et "Global Lock":
La copie de code est la suivante:
classe pulbique quelque chose {
public synchronisé void issynca () {}
public synchronisé void issyncb () {}
public statique synchronisé void cSynca () {}
public statique synchronisé void cSyncb () {}
}
Supposons que quelque chose ait deux instances x et y. Analyser les verrous acquis par les quatre ensembles d'expressions suivants.
(01) x.issynca () et x.issyncb ()
(02) x.issynca () et y.issynca ()
(03) x.csynca () et y.csyncb ()
(04) x.issynca () et quelque chose.csynca ()
(01) ne peut pas être accessible simultanément. Parce que issynca () et issyncb () sont tous deux des verrous de synchronisation qui accèdent au même objet (objet X)!
La copie de code est la suivante:
// Locktest2.java Code source
classe quelque chose {
public synchronisé void Issynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issynca");
}
} catch (InterruptedException ie) {
}
}
public synchronisé void issyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issyncb");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSynca");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSyncb");
}
} catch (InterruptedException ie) {
}
}
}
classe publique Locktest2 {
Quelque chose x = nouveau quelque chose ();
Quelque chose y = nouveau quelque chose ();
// Comparez (02) x.issynca () avec y.issynca ()
VOID PRIVÉ TEST2 () {
// Créer un nouveau T21, et T21 appellera x.issynca ()
Thread t21 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
x.issynca ();
}
}, "T21");
// Créer un nouveau T22, et T22 appellera x.issyncb ()
Thread t22 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
y.issynca ();
}
}, "T22");
t21.start ();
t22.start ();
}
public static void main (String [] args) {
LockTest2 Demo = new LockTest2 ();
Demo.Test2 ();
}
}
Résultats en cours:
La copie de code est la suivante:
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T12: issyncb
T12: issyncb
T12: issyncb
T12: issyncb
T12: issyncb
(02) est accessible en même temps. Parce qu'il n'accède pas au verrou de synchronisation du même objet, X.issynca () accède au verrou de synchronisation de x, tandis que y.issynca () accède au verrouillage de synchronisation de y.
La copie de code est la suivante:
// Locktest2.java Code source
classe quelque chose {
public synchronisé void Issynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issynca");
}
} catch (InterruptedException ie) {
}
}
public synchronisé void issyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issyncb");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSynca");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSyncb");
}
} catch (InterruptedException ie) {
}
}
}
classe publique Locktest2 {
Quelque chose x = nouveau quelque chose ();
Quelque chose y = nouveau quelque chose ();
// Comparez (02) x.issynca () avec y.issynca ()
VOID PRIVÉ TEST2 () {
// Créer un nouveau T21, et T21 appellera x.issynca ()
Thread t21 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
x.issynca ();
}
}, "T21");
// Créer un nouveau T22, et T22 appellera x.issyncb ()
Thread t22 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
y.issynca ();
}
}, "T22");
t21.start ();
t22.start ();
}
public static void main (String [] args) {
LockTest2 Demo = new LockTest2 ();
Demo.Test2 ();
}
}
Résultats en cours:
La copie de code est la suivante:
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
(03) ne peut pas être accessible simultanément. Parce que cSynca () et cSyncb () sont les deux types statiques, x.csynca () équivaut à quelque chose.issynca (), et y.csyncb () est équivalent à quelque chose être demandé en même temps.
La copie de code est la suivante:
// Locktest3.java Code source
classe quelque chose {
public synchronisé void Issynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issynca");
}
} catch (InterruptedException ie) {
}
}
public synchronisé void issyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issyncb");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSynca");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSyncb");
}
} catch (InterruptedException ie) {
}
}
}
classe publique Locktest3 {
Quelque chose x = nouveau quelque chose ();
Quelque chose y = nouveau quelque chose ();
// comparer (03) x.csynca () avec y.csyncb ()
Test de void privé3 () {
// Créer un nouveau T31, et T31 appellera x.issynca ()
Thread t31 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
x.csynca ();
}
}, "T31");
// Créer un nouveau T32, et T32 appellera x.issyncb ()
Thread t32 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
y.cSyncb ();
}
}, "T32");
t31.start ();
t32.start ();
}
public static void main (String [] args) {
LockTest3 Demo = new LockTest3 ();
Demo.Test3 ();
}
}
Résultats en cours:
La copie de code est la suivante:
T31: csynca
T31: csynca
T31: csynca
T31: csynca
T31: csynca
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
(04) peuvent être accessibles simultanément. Parce que Issynca () est une méthode d'instance, x.issynca () utilise le verrouillage de l'objet x; tandis que cSynca () est une méthode statique, quelque chose.csynca () peut comprendre qu'il s'agit d'un "verrouillage de classe" utilisé. Par conséquent, ils sont accessibles simultanément.
La copie de code est la suivante:
// Code source Locktest4.Java
classe quelque chose {
public synchronisé void Issynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issynca");
}
} catch (InterruptedException ie) {
}
}
public synchronisé void issyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": issyncb");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSynca () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSynca");
}
} catch (InterruptedException ie) {
}
}
public statique synchronisé void cSyncb () {
essayer {
pour (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (thread.currentThread (). GetName () + ": cSyncb");
}
} catch (InterruptedException ie) {
}
}
}
classe publique Locktest4 {
Quelque chose x = nouveau quelque chose ();
Quelque chose y = nouveau quelque chose ();
// Comparez (04) x.issynca () avec quelque chose.csynca ()
Test de void privé4 () {
// Créer un nouveau T41, et T41 appellera x.issynca ()
Thread t41 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
x.issynca ();
}
}, "T41");
// Créer un nouveau T42, et T42 appellera x.issyncb ()
Thread t42 = nouveau thread (
new Runnable () {
@Outrepasser
public void run () {
Quelque chose.csynca ();
}
}, "T42");
t41.start ();
t42.start ();
}
public static void main (String [] args) {
LockTest4 Demo = new LockTest4 ();
Demo.Test4 ();
}
}
Résultats en cours:
La copie de code est la suivante:
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA
T41: Issynca
T42: CSYNCA