0. Concernant la synchronisation du thread (1) Pourquoi devons-nous synchroniser le multithreading?
La synchronisation des threads fait référence à permettre à plusieurs threads en cours d'exécution de coopérer bien ensemble pour permettre à plusieurs threads d'occuper et de libérer raisonnablement des ressources au besoin. Nous utilisons des blocs de code de synchronisation et des méthodes de synchronisation en Java pour atteindre cet objectif. Par exemple, résolvez le problème de l'exécution de l'ordre non lancée multiple:
classe publique twothreadTest {public static void main (String [] args) {thread th1 = new mythread1 (); Thread th2 = new myThread2 (); th1.start (); th2.start (); }} class MyThread2 étend Thread {@Override public void run () {pour (int i = 0; i <10; i ++) Système. out.println ("COMPRESSION 1 Thread 1:" + i); }} class MyThread1 étend Thread {@Override public void run () {pour (int i = 0; i <10; i ++) Système. out.println ("COMPRESSION 1 Thread 1:" + i); }} class MyThread1 étend Thread {@Override public void run () {pour (int i = 0; i <10; i ++) Système. out.println ("Thread 2 Counter:" + I); }}Le résultat d'une exécution multi-thread dans cet état est d'insérer au hasard l'exécution à volonté, ce qui dépend entièrement de la planification de threads de JVM. Dans de nombreux cas où une exécution ordonnée est requise, cet état d'exécution aléatoire est évidemment inadapté.
classe publique threadtest {public static void main (string [] args) {mythread thread = new mythread (); Thread th1 = nouveau thread (thread); Thread th2 = nouveau thread (thread); th1.start (); th2.start (); }} class Mythread implémente Runnable {@Override public synchronisé void run () {pour (int i = 0; i <10; i ++). out.println (thread. currentThread (). getName () + "compteur:" + i); }}Après avoir utilisé la méthode de synchronisation, nous pouvons contrôler le thread pour occuper exclusivement l'objet corporel d'exécution. De cette façon, pendant le processus d'exécution, le thread peut exécuter les tâches sur le corps d'exécution à la fois et quitter l'état de verrouillage. Le JVM dépasse ensuite un autre fil pour exécuter les tâches dans le corps d'exécution à la fois.
(2) Le paradigme pour la création de threads et l'exécution:
Dans le passé, nous avons également eu notre propre paradigme de programmation pour la création de fils et la course. Généralement, nous avons défini une classe d'exécution pour réécrire la méthode RUN (), mais cette méthode rassemble le corps d'exécution et les tâches exécutées, qui n'est pas propice au découplage du point de vue de l'ingénierie logicielle. L'exécution d'un thread signifie qu'un thread exécute une tâche d'un objet via l'objet d'exécution. De ce point de vue, la séparation du prescripteur de la tâche de la classe d'exécution peut rendre les divers rôles de la programmation multithread claire et ainsi obtenir un bon découplage. Ce qui suit est le paradigme de programmation pour la création de threads et l'exécution:
classe publique FormalThreadClass {public static void main (String [] args) {thread thread = new Thread (new MyRunnable ()); thread.start (); }} class Myrunnable implémente runnable {mytask myTask = new myTask (); @Override public void run () {mytask.dotask (); }} class myTask {public void dotask () {System. out.println ("Ceci est réel tasant"); }}
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 "verrouillage 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; À l'heure actuelle, Thread B tente également d'acquérir le "verrouillage de synchronisation de l'OBJ" - Thread B ne parviendra pas à acquérir, il doit attendre que le thread A libère le "verrouillage de synchronisation d'Obj" et ne peut être exécuté que.
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".
(1) 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é".
class Myrunable Implélements Runnable {@Override public void run () {synchronisé (this) {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep 100ms 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 (); // Créer un nouveau thread "Runnable Object" T1 = nouveau thread (Demo, "T1"); // Créer un nouveau "thread T1", T1 est basé sur le thread d'objet Runnable T2 = nouveau thread (démo, "T2"); // Créer un nouveau "Thread T2", T2 est basé sur l'objet Runnable T1.Start (); // Démarrer "Thread T1" T2.Start (); // Démarrer "Thread T2"}} Résultats en cours:
LOC T1 LOOP 0T1 LOOP 1T1 LOOP 2T1 BOUCLE 3T1 BOUCLE 4T2 LOOP 0T2 LOOP 1T2 LOOP 2T2 LOOP 3T2 LOOP 4
Le résultat montre qu'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 en synchronisé (ceci) comme "objet de démo exécutable"; Par conséquent, les threads T1 et T2 partagent "verrouillage 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:
class Mythread étend Thread {public mythread (String name) {super (name); } @Override public void run () {synchronisé (this) {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms 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"); // Créer un nouveau thread "Thread T1" T2 = new Mythread ("T2"); // Créer un nouveau "thread t2" t1.start (); // Démarrer "Thread T1" T2.Start (); // Démarrer "Thread T2"}} Description du code: Comparaison 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:
Boucle T1 0T2 LOOP 0T1 LOOP 1T2 LOOP 1T1 LOOP 2T2 LOOP 2T1 LOOP 3T2 LOPE 3T1 LOOP 4T2 LOOP 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 dans Synchronisé (ceci) représente l'objet Mythread, tandis que T1 et T2 sont deux objets Mythread différents. Par conséquent, lorsque T1 et T2 exécutent synchronisés (ceci), ils acquièrent les verrous de synchronisation de différents objets. Pour la paire Demo1_1, ceci en synchronisé (this) représente l'objet myrunable; T1 et T2 partagent un objet myrunable. Par conséquent, un thread acquiert le verrou de synchronisation de l'objet, qui fera attendre un autre thread.
(2) 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é".
Class Count {// Méthodes contenant des blocs synchronisés synchronisés publics void synMethod () {synchronisé (this) {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep for 100ms System.out.println (Thread.currentThread (). GetName () + "SynMethod Loop" + I); }} catch (InterruptedException ie) {}}} // méthode asynchrone public void nonynmethod () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); System.out.println (thread.currentThread (). GetName () + "LOOP NonsynMethod" + i); }} catch (InterruptedException ie) {}}} public class Demo2 {public static void main (String [] args) {final count count = new Count (); // Créer un nouveau T1, T1 appellera la méthode SynMethod () de "Count Object" Thread T1 = nouveau thread (new Runnable () {@Override public void run () {count.synMethod ();}}, "t1"); // Créer un nouveau T2, T2 appellera la méthode NonsynMethod () du thread "Count Object" T2 = nouveau thread (new Runnable () {@Override public void run () {count.nonsynmethod ();}}, "t2"); t1.start (); // Démarrer t1 t2.start (); // Démarrer T2}} Résultats en cours:
T1 Synmethod Loop 0T2 Nonsynmethod Loop 0T1 Synmethod Loop 1T2 Nonsynmethod Loop 1T1 SYNMETHOD LOOP 2T2 Nonsynmethod Loop 2T1 Synmethod Loop 3T2 Nonsynmethod Loop 3T1 SYNMETHOD LOOP 4T2 NONSYMETHOD LOOP 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; T2 appellera la méthode NonsynMethod () de l'objet Count, qui n'est pas une méthode de synchronisation. Lorsque T1 est en cours d'exécution, bien que synchronisé (ceci) est appelé pour obtenir le «verrou de synchronisation du comte»; Il ne fait pas le blocage de T2 car T2 n'utilise pas le verrou de synchronisation "Count".
(3) 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:
Class Count {// Méthodes contenant des blocs synchronisés synchronisés publics void synMethod () {synchronisé (this) {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep for 100ms System.out.println (Thread.currentThread (). GetName () + "SynMethod Loop" + I); }} catch (InterruptedException ie) {}}} // Méthodes contenant des blocs synchronisés synchronisés publics non synto-syntadéhod () {synchronisé (this) {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); System.out.println (thread.currentThread (). GetName () + "LOOP NonsynMethod" + i); }} catch (InterruptedException ie) {}}}} public class Demo3 {public static void main (string [] args) {final count count = new Count (); // Create T1, T1 appellera la méthode SynMethod () du thread "Count Object" T1 = new Thread (new Runnable () {@Override public void run () {count.SyncMethod ();}}, "t1"); // Créer un nouveau T2, T2 appellera la méthode nonynmethod () du thread "Count Object" T2 = nouveau thread (new Runnable () {@Override public void run () {count.nonsynmethod ();}}, "t2"); t1.start (); // Démarrer t1 t2.start (); // Démarrer T2}} Résultats en cours:
T1 Synmethod Loop 0T1 SYNMETHOD LOOP 1T1 SYNMETHOD LOOP 2T1 SYNMETHOD LOOP 3T1 SYNMETHOD LOOP 4T2 NONSYMETHOD LOOP 0T2 Nonsynmethod Loop 1T2 Nonsynmethod Loop 4
Description des résultats:
Deux nouveaux fils d'enfants T1 et T2 sont créés dans le thread principal. T1 et T2 Call Synchronized (This), qui est un objet Count (Count), et T1 et T2 Count. Par conséquent, lorsque T1 est en cours d'exécution, T2 sera bloqué et T1 sera exécuté pour libérer le "verrouillage synchrone de l'objet Count" avant que T2 puisse s'exécuter.
3. Méthode synchronisée et bloc de code synchronisé
La "méthode synchronisée" utilise la méthode de modification synchronisée, tandis que le "bloc de code synchronisé" utilise le bloc de code de modification synchronisé.
Exemple de méthode synchronisée
public synchronisé void foo1 () {System.out.println ("Méthode synchronisée");} bloc de code synchronisé public void foo2 () {synchronisé (this) {System.out.println ("Méthode synchronisée"); }} Ceci dans le bloc de code synchronisé fait référence à l'objet actuel. Cela peut également être remplacé par d'autres objets, tels que celui-ci est remplacé par OBJ, puis foo2 () acquiert le verrou de synchronisation d'OBJ lorsqu'il est synchronisé (OBJ).
Les blocs de code synchronisés peuvent contrôler plus précisément les zones d'accès restreintes, et parfois fonctionner plus efficacement. Voici un exemple à démontrer:
// Demo4.java Code source classe publique Demo4 {public synchronisé void synMethod () {for (int i = 0; i <1000000; i ++); } public void synblock () {synchronisé (this) {for (int i = 0; i <1000000; i ++); }} public static void main (String [] args) {Demo4 Demo = new Demo4 (); START long, Diff; start = System.currentTimemillis (); // Obtenez l'heure actuelle (Millis) Demo.SyncMethod (); // Appel "Méthode synchronisée" Diff = System.Currenttimemillis () - Démarrer; // Obtenez "la différence de temps" System.out.println ("syncMethod ():" + diff); start = System.currentTimemillis (); // Obtenez l'heure actuelle (Millis) Demo.SyncBlock (); // Appel "Bloque de méthode synchronisée" Diff = System.Currenttimemillis () - Démarrer; // Obtenez "la différence de temps" System.out.println ("synclock ():" + diff); }} (Une fois) Résultat d'exécution:
synmethod (): 11Synblock (): 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.
(1) Le mot-clé synchronisé correspond au verrouillage de l'instance.
(2) Global Lock - Le verrou est ciblé sur une classe. Peu importe le nombre d'objets l'instance, les threads partagent le verrou.
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":
Classe pulbic quelque chose {public synchronisé void Issynca () {} public synchronisé void issyncb () {} public statique synchronisé void cSynca () {} public statique synchronisé void cSyncb () {}} public statique synchronisé csyncb () {}}. Supposons que quelque chose ait deux instances x et y. Analyser les verrous acquis par les quatre ensembles d'expressions suivants.
(1) x.issynca () et x.issyncb ()
(2) x.issynca () et y.issynca ()
(3) x.csynca () et y.csyncb ()
(4) x.issynca () et quelque chose.csynca ()
(1) 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)!
// LockTest1.java Code source Classe quelque chose {public synchronisé void issynca () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": issynca"); }} catch (InterruptedException ie) {}} public synchronisé void issyncb () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep for 100ms System.out.println (thread.currentThread (). GetName () + ": issyncb"); }} catch (InterruptedException ie) {}}} public class LockTest1 {quelque chose x = new quelque chose (); Quelque chose y = nouveau quelque chose (); // Comparez (01) x.issynca () avec x.issyncb () private void test1 () {// créer un nouveau t11, t11 appellera x.issynca () thread t11 = nouveau thread (new Runnable () {@Override public void run () {x.issynca ();}}, "t11"); // Créer un nouveau T12, T12 appellera x.issyncb () thread t12 = nouveau thread (new Runnable () {@Override public void run () {x.issyncb ();}}, "t12"); t11.start (); // Démarrer T11 T12.Start (); // Démarrer T12} public static void main (String [] args) {LockTest1 Demo = new LockTest1 (); Demo.Test1 (); }} Résultats en cours:
T11: issyncat11: issyncat11: issyncat11: issyncat12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncb
(2) peut être 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.
// LockTest2.Java Code de code source quelque chose {public synchronisé void issynca () {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": issynca"); }} catch (InterruptedException ie) {}} public synchronisé void issyncb () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": issyncb"); }} catch (InterruptedException ie) {}} public static synchronisé void cSynca () {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": cSynca"); }} catch (InterruptedException ie) {}} public static synchronisé void cSyncb () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": cSyncb"); }} catch (InterruptedException ie) {}}} public class LockTest2 {quelque chose x = new quelque chose (); Quelque chose y = nouveau quelque chose (); // Comparez (02) x.issynca () avec y.issynca () private void test2 () {// créer un nouveau t21, t21 appellera x.issynca () thread t21 = nouveau thread (new Runnable () {@Override public void run () {x.issynca ();}}, "t21"); // Créer un nouveau T22, T22 appellera x.issyncb () thread t22 = nouveau thread (new Runnable () {@Override public void run () {y.issynca ();}}, "t22"); t21.start (); // Démarrer T21 T22.Start (); // Démarrer T22} public static void main (String [] args) {LockTest2 Demo = new LockTest2 (); Demo.Test2 (); }} Résultats en cours:
T21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issynca
(3) ne peut pas être accessible simultanément
Étant donné que cSynca () et cSyncb () sont deux types statiques, x.csynca () équivaut à quelque chose.issynca (), et y.csyncb () est équivalent à quelque chose.issyncb (), ils partagent un verrou de synchronisation et ne peuvent pas être demandé en même temps.
// LockTest3.Java Code de code source quelque chose {public synchronisé void issynca () {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": issynca"); }} catch (InterruptedException ie) {}} public synchronisé void issyncb () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": issyncb"); }} catch (InterruptedException ie) {}} public static synchronisé void cSynca () {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": cSynca"); }} catch (InterruptedException ie) {}} public static synchronisé void cSyncb () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": cSyncb"); }} catch (InterruptedException ie) {}}} public class LockTest3 {quelque chose x = new quelque chose (); Quelque chose y = nouveau quelque chose (); // compare (03) x.csynca () avec y.csyncb () private void test3 () {// créer un nouveau t31, t31 appellera x.issynca () thread t31 = nouveau thread (new Runnable () {@Override public void run () {x.cSynca ();}}, "t31"); // Créer un nouveau T32, T32 appellera x.issyncb () thread t32 = nouveau thread (new Runnable () {@Override public void run () {y.cSyncb ();}}, "t32"); t31.start (); // Démarrer T31 T32.Start (); // Démarrer T32} public static void main (String [] args) {LockTest3 Demo = new LockTest3 (); Demo.Test3 (); }} Résultats en cours:
t31: cSyncAt31: cSyncAt31: cSyncAt31: cSyncAt31: cSyncAt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: csyncb
(4) peut être accessible simultanément
Parce que issynca () est une méthode d'instance, x.issynca () utilise le verrouillage de l'objet x; Alors que CSynca () est une méthode statique, quelque chose.csynca () peut comprendre qu'il est utilisé un "verrouillage de classe". Par conséquent, ils sont accessibles simultanément.
// LockTest4.java Code de code source quelque chose {public synchronisé void issynca () {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": issynca"); }} catch (InterruptedException ie) {}} public synchronisé void issyncb () {try {for (int i = 0; i <5; i ++) {Thread.Sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": issyncb"); }} catch (InterruptedException ie) {}} public static synchronisé void cSynca () {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName () + ": cSynca"); }} catch (InterruptedException ie) {}} public static synchronisé void cSyncb () {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep for 100ms System.out.println (thread.currentThread (). GetName () + ": cSyncb"); }} catch (InterruptedException ie) {}}} public class LockTest4 {quelque chose x = new quelque chose (); Quelque chose y = nouveau quelque chose (); // Comparez (04) x.issynca () avec quelque chose.cSynca () private void test4 () {// créer un nouveau t41, t41 appellera x.issynca () thread t41 = nouveau thread (new Runnable () {@Override public void run () {x.issynca ();}}, "t41"); // Créer un nouveau T42, T42 appellera x.issyncb () thread t42 = nouveau thread (new Runnable () {@Override public void run () {quelque chose.csynca ();}}, "t42"); t41.start (); // Démarrer T41 T42.Start (); // Démarrer T42} public static void main (String [] args) {LockTest4 Demo = new LockTest4 (); Demo.Test4 (); }} Résultats en cours:
T41: Issyncat42: cSyncat41: issyncat42: cSyncat41: issyncat42: cSyncat41: issyncat42: csyncat41: issyncat42: cSyncat41: issyncat42: csyncat41: issyncat42: cSynca