Heim  >  Artikel  >  Java  >  Detaillierte Erläuterung der Thread-Synchronisationsmethoden in der Java-Multithread-Programmierung

Detaillierte Erläuterung der Thread-Synchronisationsmethoden in der Java-Multithread-Programmierung

高洛峰
高洛峰Original
2017-01-05 16:32:071453Durchsuche

1. Multithread-Synchronisation:
1.1. Synchronisationsmechanismus:
Beim Multithreading versuchen möglicherweise mehrere Threads, auf eine begrenzte Ressource zuzugreifen, und dies muss verhindert werden. Daher wird ein Synchronisierungsmechanismus eingeführt: Wenn ein Thread eine Ressource verwendet, wird diese gesperrt, sodass andere Threads nicht auf diese Ressource zugreifen können, bis sie entsperrt wird.

1.2. Beispiele für gemeinsam genutzte Mitgliedsvariablen:
Mitgliedsvariablen und lokale Variablen:
Mitgliedsvariablen:

Wenn eine Variable eine Mitgliedsvariable ist, können mehrere Threads auf dieselbe zugreifen Objekt Um mit Mitgliedsvariablen zu arbeiten, teilen sich diese mehreren Threads eine Mitgliedsvariable.

Lokale Variablen:

Wenn eine Variable eine lokale Variable ist und mehrere Threads mit demselben Objekt arbeiten, verfügt jeder Thread über eine Kopie der lokalen Variablen. Die lokalen Variablen zwischen ihnen beeinflussen sich gegenseitig nicht.

Das Folgende ist ein Beispiel:
Thread-Klasse, die Runnable implementiert:

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();
   }
  }
 }
}

Verwenden Sie zwei Threads, um dasselbe Objekt in der Hauptmethode zu bedienen:

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();
}

Wenn i hier in eine Membervariable umgewandelt wird, werden 100 Zahlen ausgegeben.

1.3. Durch gemeinsame Ressourcen verursachte Lesefehler
Zum Beispiel teilen sich zwei Threads ein Number-Objekt und beziehen Daten über die getNumber-Methode der Number-Klasse. Beim Lesen und Umschreiben der Daten werden Duplikate gefunden Operation:

Erstellen Sie zunächst eine Number-Klasse:

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;
 }
}

Thread-Klasse. Die privaten Eigenschaften in der Thread-Klasse enthalten einen Verweis auf die Number-Klasse:

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

Erstellen Sie in der Hauptfunktion zwei Thread-Klassen, die Verweise auf dieselbe Instanz der Number-Klasse enthalten:

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();
}

Auf diese Weise speichert der erste Thread, wenn er die Number-Variable in Number liest, diese zuerst und schläft dann 0,1 Sekunden, und dann liest der zweite Thread die Zahlenvariable und speichert sie. Zu diesem Zeitpunkt speichern die beiden Threads dieselbe Nummer. Beim Ändern wird dieselbe Nummer zweimal geändert.

2. Implementierung des Synchronisationsmechanismus:

Synchronisiert war schon immer eine Veteranenrolle in der gleichzeitigen Multithread-Programmierung. Viele Leute werden es als Schwergewichtssperre bezeichnen, aber mit der Einführung von Java SE1. 6 Nachdem Synchronized verschiedene Optimierungen vorgenommen hat, ist es in einigen Fällen nicht mehr so ​​schwer"
Jedes Objekt in Java kann als Sperre verwendet werden.

Bei synchronisierten Methoden ist die Sperre das aktuelle Instanzobjekt.
Bei statischen synchronisierten Methoden ist die Sperre das Klassenobjekt des aktuellen Objekts
Bei synchronisierten Methodenblöcken ist die Sperre das in synchronisierten Klammern konfigurierte Objekt
Wenn ein Thread versucht, auf den synchronisierten Codeblock zuzugreifen, Beim Beenden oder Auslösen einer Ausnahme muss die Sperre zuerst aufgehoben werden.
Verwenden Sie das synchronisierte Schlüsselwort, um eine synchronisierte Methode zu erstellen Eine synchronisierte Methode. Wenn auf die synchronisierte Methode eines Objekts zugegriffen wird, bedeutet dies, dass das Objekt gesperrt ist, nicht nur die Methode Wenn eine synchronisierte Methode von einem Thread ausgeführt wird, können andere Threads nicht auf eine synchronisierte Methode des Objekts zugreifen (aber andere nicht synchronisierte Methoden aufrufen), bis die synchronisierte Methode ausgeführt wird:

Statische Situation beim Aufruf synchronisierter Methoden:

Wenn die statische synchronisierte Methode eines Objekts aufgerufen wird, ist es nicht das Objekt, in dem sich die synchronisierte Methode befindet, sondern das Klassenobjekt, das dem Objekt entspricht, in dem sich die synchronisierte Methode befindet. Auf diese Weise können andere Threads keine anderen aufrufen statische synchronisierte Methoden der Klasse, aber nicht statische synchronisierte Methoden können aufgerufen werden

Fazit: Führen Sie die statische synchronisierte Methode aus, um das Objekt zu sperren, in dem sich die Methode befindet, und führen Sie die nicht statische synchronisierte Methode aus Sperren Sie das Klassenobjekt, das der Methode entspricht. Das Folgende ist ein Beispiel für einen Thread, der eine statische Methode aufruft. Da das Klassenobjekt, das dem Objekt entspricht, in dem sich die Methode befindet, nicht aufgerufen werden kann andere statische synchronisierte Methoden des Objekts, in dem sich die Methode befindet:


In der Hauptmethode rufen die beiden Threads sie separat auf. Zwei statische synchronisierte Methoden für dasselbe Objekt:

Es kann immer nur eine statische Methode aufgerufen werden, bis die Ausführung abgeschlossen ist. 2.2 Verwenden Sie synchronisiert, um synchronisierte Codeblöcke zu erstellen Wirkung:

/**
 * 定义一个类,包含了线程类需要调用的方法
 */
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++);
  }
 }
}
Wenn Sie den synchronisierten Synchronisationscodeblock verwenden möchten, um den gleichen Effekt wie mit der synchronisierten Methode zu erzielen, können Sie diese Referenz sperren:

public static void main(String[] args) {
 Compute1 com = new Compute1();
 Thread thread1 = new Thread1(com);
 Thread thread2 = new Thread2(com);
 thread1.start();
 thread2.start();
}
2.3 Der Unterschied zwischen Synchronisierte Methoden und synchronisierte synchronisierte Codeblöcke:

Der synchronisierte synchronisierte Codeblock sperrt nur den Codeblock, und auf den Code außerhalb des Codeblocks kann weiterhin zugegriffen werden.

Die synchronisierte Methode ist eine grobkörnige Parallelitätskontrolle. Nur ein Thread kann die synchronisierte Methode zu einem bestimmten Zeitpunkt ausführen.

Der synchronisierte Codeblock ist eine feinkörnige Parallelitätskontrolle. Nur der Code im Block wird synchronisiert. Auf den Code außerhalb des Codeblocks kann gleichzeitig zugegriffen werden.
/**
 * 定义一个类,包含了线程类需要调用的方法
 */
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++);
   }
  }
 }
}

synchronized(this){
 …
}

Ausführlichere Erläuterungen zu Thread-Synchronisationsmethoden in der Java-Multithread-Programmierung finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn