Heim >Java >JavaInterview Fragen >Der Interviewer fragt Sie: Wissen Sie, was ein ABA-Problem ist?

Der Interviewer fragt Sie: Wissen Sie, was ein ABA-Problem ist?

Java学习指南
Java学习指南nach vorne
2023-07-26 15:09:451272Durchsuche

„Die Zibetkatze tauscht sich gegen den Prinzen aus.“ Die damals geliebten Konkubinen Konkubine Liu und Konkubine Li sind alle schwanger. Es ist offensichtlich, dass jeder, der einen Sohn zur Welt bringt, der Hauptpalast werden kann. Konkubine Liu war schon lange eifersüchtig und befürchtete, dass Konkubine Li einen Sohn zur Welt bringen und zur Königin ernannt werden würde, also schmiedete sie einen Plan mit Guo Huai, dem Palastverwalter Dutang, und in Zusammenarbeit mit der Hebamme Youshi, Konkubine Li starb während der Geburt im Koma. Unerwarteterweise wurde einer Zibetkatze das Fell abgezogen, es war blutig und glänzend und nahm den neugeborenen Prinzen mit. Konkubine Liu befahl der Palastmagd Kou Zhu, den Prinzen zu erwürgen, und übergab den Prinzen heimlich dem Eunuchen. Chen Lin steckte den Prinzen in einen Koffer und schickte ihn zu den Acht weisen Königen um ihn zu erziehen. Außerdem sah Zhenzong die gehäutete Zibetkatze und dachte, dass Konkubine Li ein Monster zur Welt gebracht hatte, also degradierte er sie in den kalten Palast. Bald hatte Konkubine Liu Wehen und gebar einen Sohn, der zum Prinzen ernannt wurde und ebenfalls zur Königin ernannt wurde. Sechs Jahre später starb Königin Lius Sohn unerwartet an einer Krankheit. Zhenzong hatte keine Erben mehr, also adoptierte er den Sohn seines älteren Bruders Baxian Wang (eigentlich der Prinz, der in diesem Jahr ersetzt worden war) als seinen Adoptivsohn und ernannte ihn zum Kronprinzen.

Aus dieser Geschichte geht hervor, dass der Prinz bei seiner Geburt durch eine Zibetkatze ersetzt wurde und durch eine seltsame Kombination von Umständen schließlich zurückkehrte, um der Prinz zu werden. Obwohl das Ergebnis das gleiche ist, ist der Prozess voller Wendungen und der Prinz hat wirklich ein schlimmes Schicksal. Warum diese Geschichte erzählen? Tatsächlich hat es viel mit dem Thema zu tun, das wir heute vorstellen werden. Beim gleichen Ergebnis weiß ich nicht, wie viele Operationen in der Mitte stattgefunden haben. Können wir also denken, dass sich daran nichts geändert hat? In verschiedenen Geschäftsszenarien müssen wir dieses Problem sorgfältig prüfen.

ABA-Problembeschreibung

In einem Multithread-Szenario

Problem gibt es hier eine einfache Wissenschaft zum ABA-Problem. Beispielsweise gibt es zwei Threads, die CAS-Operationen mit demselben Wert ausführen (Anfangswert). A) gleichzeitig. Die drei Threads lauten wie folgt:

  1. Thread 1, der erwartete Wert ist A, der zu aktualisierende Wert ist B
  2. Thread 2, der erwartete Wert ist A, der zu aktualisierende Wert ist B

Thread 1 erhält die CPU-Zeitscheibe Zuerst erhält Thread 2 aus anderen Gründen zuerst die CPU-Zeitscheibe. Der Grund ist blockiert. Der Wert von Thread 1 wird mit dem erwarteten Wert von A verglichen. Es wird festgestellt, dass er gleich ist, und dann wird der Wert auf B aktualisiert Zu diesem Zeitpunkt erscheint Thread 3, der erwartete Wert ist B, der zu aktualisierende Wert ist A und der Wert von Thread 3 ist derselbe wie der erwartete Wert. Vergleichen Sie den Wert B und aktualisieren Sie ihn, wenn festgestellt wird, dass er gleich ist der Wert auf A. Zu diesem Zeitpunkt erholt sich Thread 2 von der Blockierung und erhält die CPU-Zeitscheibe. Zu diesem Zeitpunkt wird der Wert von Thread 2 mit dem erwarteten Wert A verglichen. Wenn festgestellt wird, dass er gleich ist, wird der Wert aktualisiert zu B. Obwohl Thread 2 den Vorgang ebenfalls abgeschlossen hat, weiß Thread 2 nicht, dass der Wert den Änderungsprozess von A->B->A durchlaufen hat.

Gib mir ein konkretes Beispiel

Xiao Ming hat 50 Yuan vom Geldautomaten abgehoben, es gab zwei Threads und der Kontostand wurde gleichzeitig von 100 auf 50 geändert Zeit:

  • Thread 1 (Geldautomat): Aktuellen Wert 100 abrufen, Aktualisierung auf 50 erwarten;
  • Thread 2 (Geldautomat): Aktuellen Wert 100 abrufen, Aktualisierung auf 50 erwarten;
  • Thread 1 erfolgreich ausgeführt, Thread 2 ist aus irgendeinem Grund blockiert;
  • Zu diesem Zeitpunkt überweist jemand 50 an Xiao Ming;
  • Thread 3 (Standard): Holen Sie sich den aktuellen Wert von 50 und erwarten Sie ihn auf 100 aktualisiert werden. Zu diesem Zeitpunkt wird Thread 3 erfolgreich ausgeführt und der Kontostand wird 100;
  • Thread 2 erholt sich vom Block und erhält 100. Nach dem Vergleich wird der Kontostand weiterhin auf 50 aktualisiert.

An dieser Stelle können Sie sehen, dass der tatsächliche Saldo sein sollte: 100(100-50+50),但是实际上变为了50(100-50+50-50)Dies ist das ABA-Problem, das zu falschen Einreichungsergebnissen führt.

Lösung

Um das ABA-Problem zu lösen, können Sie eine Versionsnummer hinzufügen. Jedes Mal, wenn der Wert des Speicherorts V geändert wird, wird die Versionsnummer um 1 erhöht

Codebeispiel

ABA-Probleme durch AtomicStampedReference lösen

  • AtomicStampedReference behält den Objektwert und die Versionsnummer intern bei den Anfangswert übergeben und ursprüngliche Version Nr.;

  • Wenn AtomicStampedReference den Objektwert festlegt, müssen sowohl der Objektwert als auch der Statusstempel den erwarteten Wert erfüllen, damit der Schreibvorgang erfolgreich ist.

private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(100,1);

public static void main(String[] args) {
//第一个线程
 new Thread(() -> {
  System.out.println("t1拿到的初始版本号:" + atomicStampedReference.getStamp());
  
  //睡眠1秒,是为了让t2线程也拿到同样的初始版本号
  try {
   TimeUnit.SECONDS.sleep(1);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  atomicStampedReference.compareAndSet(100, 101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
  atomicStampedReference.compareAndSet(101, 100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
 },"t1").start();
 
  // 第二个线程
 new Thread(() -> {
  int stamp = atomicStampedReference.getStamp();
  System.out.println("t2拿到的初始版本号:" + stamp);
  
  //睡眠3秒,是为了让t1线程完成ABA操作
  try {
   TimeUnit.SECONDS.sleep(3);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("最新版本号:" + atomicStampedReference.getStamp());
  System.out.println(atomicStampedReference.compareAndSet(100, 2019,stamp,atomicStampedReference.getStamp() + 1) + "\t当前值:" + atomicStampedReference.getReference());
 },"t2").start();
}

1. Threads t1 und t2 erhalten die gleiche anfängliche Versionsnummer
3. Thread t1 schließt den ABA-Vorgang ab und die Versionsnummer wird auf 3
4 erhöht . Thread t2 Der CAS-Vorgang ist zu 3 geworden, was nicht mit der Versionsnummer 1 übereinstimmt, die zuvor von Thread t2 erhalten wurde. Das Ergebnis der Ausführung:

Lösen Sie das ABA-Problem durch AtomicMarkableReference

, Der einzige Unterschied zwischen AtomicMarkableReference besteht darin, dass zur Identifizierung der Referenz nicht mehr int verwendet wird, sondern eine boolesche Variable verwendet wird, um anzugeben, ob die Referenzvariable geändert wurde.

t1拿到的初始版本号:1
t2拿到的初始版本号:1
最新版本号:3
false 当前值:100

1. Der Anfangswert ist 100, die Anfangsversionsnummer wurde nicht geändert. Thread t1 und t2 haben die gleiche Anfangsversionsnummer erhalten und wurden nicht geändert Operation, und die Versionsnummer wurde geändert true 4. Thread t2 hat den CAS-Vorgang abgeschlossen. Die Versionsnummer ist nicht gleich der von Thread t2 zuvor erhaltenen Versionsnummer

AtomicStampedReference可以给引用加上版本号,追踪引用的整个变化过程,如:A -> B -> C -> D -> A,通过AtomicStampedReference,我们可以知道,引用变量中途被更改了3次。但是,有时候,我们并不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了AtomicMarkableReference

Ausführung Ergebnis:

t1版本号是否被更改:false
t2版本号是否被更改:false
是否更改过:true
false 当前值:100

多说几句

以上是本期关于CAS领域的一个经典ABA问题的解析,不知道你在实际的工作中有没有遇到过,但是在面试中这块是并发知识考查的重点。如果你还没接触过此类的问题,我的建议是你自己将上面的代码运行一下,结合理论去理解一下ABA问题所带来的问题以及如何解决他,这对你日后的开发工作也是有莫大的帮助的!

Das obige ist der detaillierte Inhalt vonDer Interviewer fragt Sie: Wissen Sie, was ein ABA-Problem ist?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:Java学习指南. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen