Heim  >  Artikel  >  Java  >  Erfahren Sie mehr über die drei Elemente der gleichzeitigen Java-Programmierung

Erfahren Sie mehr über die drei Elemente der gleichzeitigen Java-Programmierung

WBOY
WBOYnach vorne
2022-04-22 11:54:482663Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über Java, in dem hauptsächlich Fragen im Zusammenhang mit den drei Elementen der gleichzeitigen Programmierung vorgestellt werden, einschließlich Atomizität, Sichtbarkeit, Ordnung, deren Ursachen und Definitionen usw. Schauen wir uns hoffentlich den folgenden Inhalt an es wird für alle hilfreich sein.

Erfahren Sie mehr über die drei Elemente der gleichzeitigen Java-Programmierung

Empfohlene Studie: „Java-Video-Tutorial

1 Atomizität

1.1 Die Definition von Atomizität

Atomizität bezieht sich auf eine oder mehrere Operationen, die entweder alle ausgeführt oder nicht unterbrochen werden durch andere Vorgänge während der Ausführung oder werden überhaupt nicht ausgeführt.

1.2 Ursachen für Atomizitätsprobleme

Thread-Switching ist die Ursache für Atomizitätsprobleme. Thread-Switching dient der Verbesserung der CPU-Auslastung.

Am Beispiel von count++ sind mindestens drei CPU-Anweisungen erforderlich:

  • Anweisung 1: Zuerst muss die Variable count aus dem Speicher in das CPU-Register geladen werden.
  • Anweisung 2: Danach führen Sie Folgendes aus +1-Operation im Register;
  • Anweisung 3: Schreiben Sie abschließend das Ergebnis in den Speicher (der Caching-Mechanismus bewirkt, dass der CPU-Cache und nicht der Speicher geschrieben wird).

Wir nehmen an, dass count=0 ist. Wenn Thread A den Thread wechselt, nachdem Anweisung 1 ausgeführt wurde, und Thread A und Thread B gemäß der Reihenfolge in der Abbildung unten ausgeführt werden, werden wir feststellen, dass beide Threads die Operation count+= ausgeführt haben 1, aber das erhaltene Ergebnis ist nicht 2, wie wir erwartet hatten, sondern 1.

1.3 Atomare Operationen

In einer Multithread-Umgebung garantiert Java nur, dass Variablen und Zuweisungsoperationen grundlegender Datentypen atomar sind (Hinweis: In einer 32-Bit-JDK-Umgebung für 64-Bit-Daten Das Lesen ist keine atomare Operation*, wie z. B. long, double)

1.4 So lösen Sie das Atomizitätsproblem

Wenn wir sicherstellen können, dass sich Änderungen an gemeinsam genutzten Variablen gegenseitig ausschließen, unabhängig davon, ob es sich um eine Single-Core-CPU oder eine handelt Multi-Core-CPU. Dadurch wird die Atomizität gewährleistet. Durch Sperren können Atomizitätsprobleme gelöst werden, z. B. durch die Verwendung von „Synchronized“ und „Lock“.

2 Sichtbarkeit

2.1 Sichtbarkeitsdefinition

Sichtbarkeit bedeutet, dass, wenn mehrere Threads eine gemeinsam genutzte Variable bearbeiten, andere Threads sofort das Ergebnis der Änderung sehen können, nachdem einer der Threads die Variable geändert hat.

2.2 Ursachen für Sichtbarkeitsprobleme

Die Datenkonsistenz zwischen CPU-Cache und Speicher ist die Ursache für Sichtbarkeitsprobleme. Der CPU-Cache soll die Effizienz der CPU verbessern.

2.3 Lösung des Sichtbarkeitsproblems

Die Ursache des Sichtbarkeitsproblems ist der CPU-Cache. Dann können wir den CPU-Cache deaktivieren.

  • flüchtiges Feld kann den CPU-Cache deaktivieren und Sichtbarkeitsprobleme lösen.
  • Sowohl Synchronisierung als auch Sperren können die Sichtbarkeit gewährleisten.

2.4 Was sind Sichtbarkeitsregeln?

Die Sichtbarkeitsregel ist die Happens-Before-Regel.

Passiert-Vorher-Regel:

  • Einfach ausgedrückt: Das Ergebnis des vorherigen Vorgangs ist für nachfolgende Vorgänge sichtbar.
  • Happens-Before schränkt das Optimierungsverhalten des Compilers ein. Obwohl der Compiler optimieren darf, muss er nach der Optimierung die Happens-Before-Regeln einhalten.

2.5 Passiert vor Regeln

  • Programmsequenzregeln

In einem Thread findet entsprechend der Programmsequenz die vorherige Operation statt – vor jeder nachfolgenden Operation.

class Example {
  public void test() {
    int x = 42;   ①
    int y = 20;   ②
  }
 
}

① Passiert – bevor ②.

  • Regeln für flüchtige Variablen

Ein Schreibvorgang für eine flüchtige Variable wird ausgeführt, bevor nachfolgende Lesevorgänge für diese flüchtige Variable ausgeführt werden.

  • Transitivitätsregel

Wenn A vor B geschieht und B vor C geschieht, dann geschieht A vor C.

class Example {
  int x = 0;
  volatile int y = 0;
  public void writer() {
    x = 42;      ①
    y = 1;       ②
  }
  public void reader() {
    if (y == 1) {  ③
      // 这里x会是多少呢?
    }
  }
}
  • ① Passiert – bevor ②, Regel 1 – sequentielle Regel erfüllt.
  • ② Passiert – bevor ③, erfüllt Regel 2 – Regel für flüchtige Variablen.
  • ① Passiert – bevor ③, erfüllt Regel 3 – Transitivitätsregel. Wenn y == 1, dann ist x = 42;
  • 管程是一种通用的同步原语,在 Java 中指的就是 synchronized,synchronized 是 Java 里对管程的实现。

synchronized (this) { //此处自动加锁
  // x是共享变量,初始值=10
  if (this.x < 12) {
    this.x = 12; 
  }  
} //此处自动解锁

假设 x 的初始值是 10,线程 A 执行完代码块后 x 的值会变成 12(执行完自动释放锁);

线程 B 进入代码块时,能够看到线程 A 对 x 的写操作,也就是线程 B 能够看到 x==12。

  • 线程 start() 规则

它是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。

  • 线程 join() 规则

它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作。

3 有序性

3.1 有序性的定义

有序性,即程序的执行顺序按照代码的先后顺序来执行。

3.2 有序性问题原因

编译器为了优化性能,有时候会改变程序中语句的先后顺序。

例如:“a=6;b=7;”编译器优化后可能变成“b=7;a=6;”,在这个例子中,编译器调整了语句的顺序,但是不影响程序的最终结果。

以双重检查代码为例:

public class Singleton {
  static Singleton instance;
  static Singleton getInstance(){
    if (instance == null) {    ①
      synchronized(Singleton.class) {
        if (instance == null)
          instance = new Singleton();  ②
        }
    }
    return instance;
  }
}

上面的代码有问题,问题在 ② 操作上:经过优化后的执行路径是这样的:

  1. 分配一块内存 M;
  2. 将 M 的地址赋值给 instance 变量;
  3. 最后在内存 M 上初始化 Singleton 对象。

优化后会导致什么问题呢?我们假设线程 A 先执行 getInstance() 方法,当执行完 ① 时恰好发生了线程切换,切换到了线程 B 上;如果此时线程 B 也执行 getInstance() 方法,那么线程 B 在执行第一个判断时会发现 instance != null ,所以直接返回 instance,而此时的 instance 是没有初始化过的,如果我们这个时候访问 instance 的成员变量就可能触发空指针异常。

如何解决双重检查问题?变量用 volatile 来修饰,禁止指令重排序

public class Singleton {
  static volatile Singleton instance;
  static Singleton getInstance(){
    if (instance == null) {    ①
      synchronized(Singleton.class) {
        if (instance == null)
          instance = new Singleton();  ②
        }
    }
    return instance;
  }
}

推荐学习:《java视频教程

Das obige ist der detaillierte Inhalt vonErfahren Sie mehr über die drei Elemente der gleichzeitigen Java-Programmierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen