Maison  >  Article  >  Java  >  Décrire brièvement la mise en œuvre multithread et la communication synchrone mutuellement exclusive

Décrire brièvement la mise en œuvre multithread et la communication synchrone mutuellement exclusive

Y2J
Y2Joriginal
2017-05-08 13:50:371084parcourir

L'éditeur suivant vous proposera une brève discussion sur l'implémentation multithread Java et la communication d'exclusion mutuelle synchrone. L'éditeur le trouve plutôt bon, je vais donc le partager avec vous maintenant et le donner comme référence pour tout le monde. Suivons l'éditeur pour y jeter un œil

Compréhension approfondie du multi-threading JavaCet article comprend et maîtrise principalement le multi-threading sous trois aspects :

1 . L'implémentation du multi-threading, en héritant de la classe Thread et en implémentant l'interface Runnable, ainsi que les similitudes et les différences.

2. Comment utiliser synchronisé en synchronisation multi-thread et exclusion mutuelle.

3. Comment utiliser notify(), notifyAll() et wait() dans une communication multithread, ainsi que des implémentations simples de code générateur et consommateur.

Ce qui suit est une explication détaillée du multi-threading en Java :

1 : Implémentation du multi-threading

Réaliser le multithreading en héritant de la classe Threa est principalement divisé en trois étapes suivantes :

Première étape : hériter du Thread et implémenter la méthode run() dans le Classe de fil.

Étape 2 : Définir une instance de la sous-classe Thread.

Étape 3 : Démarrez le thread en appelant la méthode start() de la classe Thread.

Ce qui suit est une implémentation de code simple :

class myThread extends Thread{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }

}
public class ThreadTest {

  public static void main(String[] args) {
    myThread mythread=new myThread();
    mythread.setName("子线程");
    mythread.start();
  }

}

Plusieurs méthodes utilisées dans le fil de discussion ci-dessus : La méthode Thread.currentThraed().getName() obtient le courant Le nom du fil. mythread.setName("fil enfant"); Renommez le fil mythread en "fil enfant".

Réaliser le multithreading en implémentant l'interface Runnable est principalement divisé en les étapes suivantes :

Première étape : implémenter run( dans Runnable méthode d'interface). Générez une instance de Runnable.

Étape 2 : Définissez une classe Thread et transmettez l'instance Runnable ci-dessus à la méthode constructeur de la classe Thread.

Étape 3 : Démarrez le thread en appelant la méthode start() de la classe Thread.

Ce qui suit est une implémentation de code simple :

class myRunnable implements Runnable{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }
}
public class ThreadTest {

  public static void main(String[] args) {
    myRunnable myrunnable = new myRunnable();
    Thread mythread=new Thread(myrunnable);
    mythread.setName("子线程");
    mythread.start();
  }
}

Puisque le multithreading peut être obtenu en héritant de la classe Thread et en implémentant la méthode Runnable, quels sont les deux méthodes ? Quelle est la différence ? Jetons un coup d'œil à la différence entre les deux à travers une catégorie d'achat de billets :

Supposons qu'il y ait 100 billets au total à la billetterie, et que la vente des billets s'effectue à travers trois guichets. pour ouvrir trois fils de discussion différents pour réaliser l'achat de billets : Tout d'abord, regardons comment réaliser l'achat de billets via la classe Thread :

class myThread extends Thread{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }
}
public class ThreadTest {
  public static void main(String[] args) {
    myThread m1=new myThread();
    myThread m2=new myThread();
    myThread m3=new myThread();
    m1.setName("窗口1");
    m2.setName("窗口2");
    m3.setName("窗口3");
    m1.start();
    m2.start();
    m3.start();
  }
}

Le résultat est trop long et je ne le montrerai pas. Vous pouvez le voir. que les trois fenêtres d'origine ont acheté conjointement 100 billets, mais en conséquence, chaque fenêtre a acheté 100 billets. C'est facile à comprendre car chaque fenêtre est un objet indépendant avec son propre n=100. Par conséquent, il n'est pas possible d'implémenter la fonction d'achat de billets via la classe Thread. En fait, la méthode Thread est utilisée pour implémenter le multi-threading, dans lequel le code exécuté par chaque thread n'est pas le même morceau de code.

Voyons comment implémenter l'interface Runnable pour implémenter la fonction d'achat de billets :

class myRunnable implements Runnable{
  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
  }
}
public class ThreadTest {
  public static void main(String[] args) {
    myRunnable myrunnable=new myRunnable();
    Thread m1=new Thread(myrunnable);
    Thread m2=new Thread(myrunnable);
    Thread m3=new Thread(myrunnable);
    m1.setName("窗口1");
    m2.setName("窗口2");
    m3.setName("窗口3");
    m1.start();
    m2.start();
    m3.start();
  }
}

On peut voir que les trois fils de discussion ci-dessus partagent le même sous-classe exécutable, il suffit donc d'ouvrir trois threads pour exécuter le même code exécutable. Il n’y aura donc aucune situation où vous devrez acheter 300 billets. Mais il y a encore des problèmes avec ce programme. Nous améliorerons ce programme après avoir parlé de la synchronisation et de l'exclusion mutuelle des threads suivants.

2 : Comment utiliser synchronisé et volatile dans la synchronisation multithread et l'exclusion mutuelle.

Interceptez maintenant une section du problème survenu lors de l'exécution du code ci-dessus et analysez comment le problème s'est produit, puis utilisez synchronisé pour résoudre le problème.

:Fenêtre 2…1
:Fenêtre 1…1
:Fenêtre 3…1
:Fenêtre 1…2
:Fenêtre 2…2
:Fenêtre 1… 3
:Fenêtre 3…2
:Fenêtre 1…4
:Fenêtre 2…3
:Fenêtre 1…5
:Fenêtre 3…3
:Fenêtre 1…6
:Fenêtre 2…4

Le résultat du code ci-dessus est généré en implémentant l'interface Runnable. Comment les fenêtres 1, 2 et 3 ci-dessus génèrent-elles 1 en même temps ?

  int n=100;
  public void run() {
    while (true) {
    if (n > 0) {
System.out.println(":"Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }

Il s'agit du même morceau de code exécuté par trois threads. Une des raisons du résultat ci-dessus peut être que lorsque la fenêtre 2 termine son exécution et génère i=1, la machine virtuelle exécute la fenêtre 2. 2 Exécuter. sortie I. A ce moment, i n'a pas exécuté ++, donc la valeur de i est toujours 1. A ce moment, la machine virtuelle donne le droit d'exécution à la fenêtre 3. A ce moment, la sortie i par la fenêtre 3 est toujours 1, et le programme produit le problème ci-dessus. La raison principale est qu'il existe une variable publique i et que la valeur de i n'est pas synchronisée pendant l'exécution du programme. Le corps de la boucle for ci-dessus doit être exécuté séparément avant que d'autres threads puissent s'emparer de la machine virtuelle. Le mot-clé Synchronized est utilisé pour garantir qu'un thread n'est pas préempté par d'autres threads lors de l'exécution d'une section de ressources publiques.

Le bloc de code modifié par synchronisé est appelé bloc de code synchronisé, et la méthode modifiée par synchronisé est appelée méthode synchronisée. La fonction d'achat de billets est implémentée en ajoutant le mot-clé synchronisé ci-dessous :

class myRunnable implements Runnable {
  int n = 100;

  public void run() {
    while (true) {
      synchronized (this) {
        if (n > 0) {
          if (n % 10 == 0) {
            try {
              Thread.currentThread().sleep(10);
            } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            }
          }
          System.out.println(":" + Thread.currentThread().getName()
              + "..." + n--);
        } else {
          break;
        }
      }
    }
  }
}

public class ThreadTest {
  public static void main(String[] args) {
    myRunnable myrunnable = new myRunnable();
    Thread m1 = new Thread(myrunnable);
    Thread m2 = new Thread(myrunnable);
    Thread m3 = new Thread(myrunnable);
    m1.setName("窗口1");
    m2.setName("窗口2");
    m3.setName("窗口3");
    m1.start();
    m2.start();
    m3.start();
  }
}

À ce stade, la fonction de vente de billets peut être complétée correctement.

上面代码中synchronized(this)中的this代表的是当前的对象,因为三个线程执行的都是myRunnable 的对象,所以三个线程公用的是同一个锁,其实这个this可以用任何的对象来代替,一般我们可以 String str=new String(“”);虽然str的值为空字符串,但是也是一个对象。Synchronized实现互斥的原理是每一个对象都有一个特定的变量值,当任何一个线程调用了synchronized想要进入公共资源区时,先判断该变量的值,若该变量的值为0则可以进入公共资源区,进程在进入公共资源区之前先把对象的中的该变量值变为1,出同步区后再将该变量的值变为0,从而实现线程互斥访问公共资源。

三:多线程的通讯中的notify(),notifyAll(),及wait(),的使用方法,以及简单的生成者和消费者的代码实现。

在讲解notify(),notifyAll(),wait()之前,先看看生产者和消费者问题:生产者生产面包,消费者消费面包,但是存放面包的容器有限,生产者一次最多只能生产20个面包,消费者每次在容器中拿一个面包。通过分析可以知道,当生产者生产了20个面包之后必须停下来,等容器里的面包数目小于20个时再继续生产,消费者看到容器里面面包个数为0时也必须停下来,等到有面包时才能消费。这时候就涉及到了生产者和消费者的通信。notify()是用于唤醒等待队列中的线程,wait()用于阻塞当前线程。Notify和wait()都必须用于synchronized修饰的同步代码块或同步方法中。

下面直接看生产者消费者代码。

class Consumer implements Runnable {
  Clerk clerk;
  Consumer(Clerk clerk) {
    this.clerk = clerk;
  }
  public void run() {
    while(true)
    clerk.consumeProduct();
  }
}
class Producter implements Runnable {
  Clerk clerk;
  Producter(Clerk clerk)
  {
    this.clerk = clerk;
  }
  public void run() {
    while(true)
    clerk.addProduct();
  }
}
class Clerk {
  int product ;
  public synchronized void consumeProduct() {
    while (true) {
      if (product <= 0) {
        try {
          wait();
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } else {
        product--;
        notifyAll();
        System.out.println("消费者消费了:" + product);
      }
    }
  }
  public synchronized void addProduct() {
    if (product > 20) {
      try {
        wait();
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    } else {
      product++;
      notifyAll();
      System.out.println("生产者生产了:" + product);
    }
  }

}
public class Test {
  public static void main(String[] args) {
    Clerk clerk=new Clerk();
    Consumer consumer=new Consumer(clerk);
    Thread c=new Thread(consumer);
    Producter producter=new Producter(clerk);
    Thread p=new Thread(producter);
    c.start();
    p.start();
  }
}

【相关推荐】

1.Java免费视频教程

2.全面解析Java注解

3.阿里巴巴Java开发手册

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
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