Maison > Java > javaDidacticiel > Explication détaillée des méthodes de synchronisation des threads dans la programmation multithread Java

Explication détaillée des méthodes de synchronisation des threads dans la programmation multithread Java

高洛峰
Libérer: 2017-01-05 16:32:07
original
1503 Les gens l'ont consulté

1. Synchronisation multi-thread :
1.1. Mécanisme de synchronisation :
En multi-thread, plusieurs threads peuvent tenter d'accéder à une ressource limitée, et cela doit être évité. Par conséquent, un mécanisme de synchronisation est introduit : lorsqu'un thread utilise une ressource, celle-ci est verrouillée, de sorte que les autres threads ne peuvent pas accéder à cette ressource jusqu'à ce qu'elle soit déverrouillée.

1.2. Exemples de variables membres partagées :
Variables membres et variables locales :
Variables membres :

Si une variable est une variable membre, alors plusieurs threads peuvent accéder à la même object Pour opérer sur les variables membres, ces multiples threads partagent une variable membre.

Variables locales :

Si une variable est une variable locale et que plusieurs threads opèrent sur le même objet, chaque thread aura une copie de la variable locale. Les variables locales entre elles ne s’influencent pas.

Ce qui suit est un exemple :
Classe Thread qui implémente Runnable :

class MyThread3 implements Runnable{
 
 //两个线程操作同一个对象,共享成员变量
 //int i;
 @Override
 public void run() {
  //两个线程操作同一个对象,各自保存局部变量的拷贝
  int i = 0;
  while(i<100){
   System.out.println(i);
   i++;
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }
}
Copier après la connexion

Utilisez deux threads pour faire fonctionner le même objet dans la méthode principale :

public static void main(String[] args) {
 
 MyThread3 myThread = new MyThread3();
 //下面两个线程对同一个对象(Runnable的实现类对象)进行操作
 Thread thread = new Thread(myThread);
 Thread thread2 = new Thread(myThread);
 //各自保存局部变量的拷贝,互不影响,输出200个数字
 thread.start();
 thread2.start();
}
Copier après la connexion

Si i est transformé en variable membre ici, 100 nombres seront affichés.

1.3. Erreurs de lecture causées par des ressources partagées
Par exemple, deux threads partagent un objet Number et obtiennent des données via la méthode getNumber de la classe Number, des doublons sont trouvés. opération :

Créez d'abord une classe Number :

class Number{
 private int number = 10;
 public String getNumber(int i){
  if(number > 0){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   number -= i;
   return "取出"+i+"成功,剩余数量:"+number;
  }
  return "取出"+i+"失败,剩余数量:"+number;
 }
}
Copier après la connexion

Classe Thread. Les propriétés privées de la classe thread contiennent une référence à la classe Number :

class MyThread4 extends Thread{
 
 //两个线程操作同一个对象,共享成员变量
 Number number;
 public MyThread4(Number number){
  this.number = number;
 }
 @Override
 public void run() {
  System.out.println(number.getNumber(8));
 }
}
Copier après la connexion

. Créez deux classes de thread dans la fonction principale, contenant des références à la même instance de classe Number :

public static void main(String[] args) {
 
 Number number = new Number();
 //两个线程操作同一个对象,共享对象number的成员变量number
 MyThread4 myThread = new MyThread4(number);
 MyThread4 myThread2 = new MyThread4(number);
 myThread.start();
 myThread2.start();
}
Copier après la connexion

De cette façon, lorsque le premier thread lit la variable number dans Number, il l'enregistre d'abord puis dort 0,1 secondes, puis le deuxième thread lit la variable numérique et l'enregistre. À ce moment, les deux threads enregistrent le même numéro. Lors de la modification, le même numéro est modifié deux fois.

2. Implémentation du mécanisme de synchronisation :

La synchronisation a toujours été un rôle vétéran dans la programmation simultanée multithread. Beaucoup de gens l'appelleront un verrou lourd, mais avec l'introduction de Java SE1. 6 Après que Synchronized ait fait diverses optimisations, dans certains cas, ce n'est pas si lourd"
Chaque objet en Java peut être utilisé comme verrou.

Pour les méthodes synchronisées, le verrou est l'objet d'instance actuel.

Pour les méthodes synchronisées, le verrou est l'objet d'instance actuel.
Pour les méthodes synchronisées statiques, le verrou est l'objet Class de l'objet actuel
Pour les blocs de méthodes synchronisées, le verrou est l'objet configuré entre parenthèses synchronisées
Quand un thread tente d'accéder au bloc de code synchronisé, il doit d'abord obtenir le verrou. Le verrou doit être libéré lors de la sortie ou du lancement d'une exception

2.1. Utilisez le mot-clé synchronisé pour créer une méthode synchronisée :

Utilisez le mot-clé synchronisé. une méthode synchronisée. Chaque objet a un verrou, ou un moniteur. Lors de l'accès à la méthode synchronisée d'un objet, cela signifie que l'objet est verrouillé, pas seulement la méthode

De cette façon, si la méthode synchronisée d'un objet. is Lorsqu'une méthode synchronisée est exécutée par un thread, les autres threads ne peuvent accéder à aucune méthode synchronisée de l'objet (mais peuvent appeler d'autres méthodes non synchronisées) jusqu'à ce que la méthode synchronisée soit exécutée :

Situation d'appel de méthode synchronisée statique :
Lorsque la méthode statique synchronisée d'un objet est appelée, ce n'est pas l'objet où se trouve la méthode synchronisée, mais l'objet Class correspondant à l'objet où se trouve la méthode synchronisée. De cette façon, les autres threads ne peuvent pas en appeler d'autres. méthodes synchronisées statiques de la classe. , mais vous pouvez appeler des méthodes synchronisées non statiques

Conclusion : exécutez la méthode synchronisée statique pour verrouiller l'objet où se trouve la méthode et exécutez la méthode synchronisée non statique pour. verrouille l'objet Class correspondant à la méthode.

Les éléments suivants sont nombreux. Un exemple de thread appelant une méthode statique Puisque l'objet Class correspondant à l'objet où se trouve la méthode est verrouillé, les autres threads ne peuvent pas appeler. autres méthodes statiques synchronisées de l'objet où se trouve la méthode :

/**
 * 定义一个类,包含了线程类需要调用的方法
 */
class Compute1{
 //这时如果某个线程调用该方法,
 //将锁定synchronized方法所在对象对应的class对象,
 //而不是锁定synchronized方法所在对象
 public synchronized static void execute(){
  for(int i = 0; i<100; i++){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("compute1:execute1 " + i++);
  }
 }
 public synchronized static void execute2(){
  for(int i = 0; i<100; i++){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("compute1:execute2 " + i++);
  }
 }
}
Copier après la connexion

Dans la méthode principale, les deux threads les appellent séparément Deux méthodes statiques synchronisées sur le même objet :

public static void main(String[] args) {
 Compute1 com = new Compute1();
 Thread thread1 = new Thread1(com);
 Thread thread2 = new Thread2(com);
 thread1.start();
 thread2.start();
}
Copier après la connexion

Une seule méthode statique peut être appelée à la fois jusqu'à ce que l'exécution soit terminée. 2.2 Utilisez synchronisé pour créer des blocs de code synchronisés :

Réussi. Utilisez un bloc de code de synchronisation synchronisé pour verrouiller un objet, qui sert de marque exécutable pour réaliser la synchronisation. effet :


Si vous souhaitez utiliser le bloc de code de synchronisation synchronisé pour obtenir le même effet qu'en utilisant la méthode synchronisée, vous pouvez verrouiller cette référence :
/**
 * 定义一个类,包含了线程类需要调用的方法
 */
class Compute1{
 //通过同步代码块锁定object1对象进行锁定了其他同样的synchronized代码块
 private Object object1 = new Object();
 public void execute(){
  synchronized(object1){
   for(int i = 0; i<100; i++){
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("compute1:execute1 " + i++);
   }
  }
 
 }
 public synchronized void execute2(){
  synchronized(object1){
   for(int i = 0; i<100; i++){
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("compute1:execute2 " + i++);
   }
  }
 }
}
Copier après la connexion

La différence entre. méthodes synchronisées et blocs de code synchronisés synchronisés :
synchronized(this){
 …
}
Copier après la connexion
Le bloc de code synchronisé synchronisé verrouille uniquement le bloc de code, et le code en dehors du bloc de code est toujours accessible.


La méthode synchronisée est un contrôle de concurrence grossier. Un seul thread peut exécuter la méthode synchronisée à un moment donné.

Le bloc de code synchronisé est un contrôle de concurrence précis. Seul le code du bloc sera synchronisé. Le code en dehors du bloc de code est accessible par d'autres threads en même temps.


Pour des explications plus détaillées sur les méthodes de synchronisation des threads dans la programmation multi-thread Java, veuillez faire attention au site Web PHP chinois !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal