目次
#AtomicMarkableReference を通じて ABA 問題を解決する" >#AtomicMarkableReference を通じて ABA 問題を解決する
ホームページ Java &#&面接の質問 面接官は「ABA 問題とは何か知っていますか?」と尋ねます。

面接官は「ABA 問題とは何か知っていますか?」と尋ねます。

Jul 26, 2023 pm 03:09 PM
cas

王子のためのジャコウネコ

問題の詳細を説明する前に、短い物語を見てみましょう:

北宋の宋真宗皇后の死後、彼の最愛の側室である劉皇后と李皇后はともに妊娠しており、息子を産んだ方が正宮になる可能性が高いのは明らかでした。劉妃は長年嫉妬しており、李妃が男の子を産んで王妃にされるのではないかと恐れ、郭淮、宮司の杜唐、そして産婆のヨウシの協力を得て計画を立てた。出産時に昏睡状態で亡くなったが、なんとジャコウネコの毛皮が剥げてしまい、血まみれでテカテカになって、生まれたばかりの王子を連れ去ってしまったのだ。劉妃は宮廷侍女コウ・朱に王子を絞め殺すように命じたが、コウ・朱はそれに耐えられず、密かに宦官の陳林に引き渡し、陳林は王子をスーツケースに入れて八賢王のもとへ送った。彼を育てるために。さらに、皮を剥いだジャコウネコを見た真宗は、李妃が化け物を産んだのではないかと思い、李妃を寒宮に降格させた。やがて、劉妃が陣痛を迎えて男の子を出産したため、その子が王子となり、劉妃も王妃に任命された。予期せぬことに、6年後、劉女王の息子は病気で亡くなりました。鎮宗には後継者がいなかったため、兄の王八賢(実際にはその年に更迭された王子)の子を養子として迎え、皇太子に据えた。

この物語からわかるのは、王子は生まれたときにジャコウネコに置き換えられ、その後、奇妙なことが重なって最終的に王子に戻ったということです。結果は同じでも、その過程は紆余曲折あって、王子は本当に運命が悪い。

なぜこの話をするのか?実は、これは今日紹介する問題と大きく関係しています。同じ結果ですが、途中で何回操作が発生したか分かりませんが、変化がないと考えて良いでしょうか?さまざまなビジネス シナリオにおいて、この問題を慎重に検討する必要があります。

#ABA 問題の説明

マルチスレッド シナリオでは、

CAS が表示されます ABA 問題, ここに ABA 問題についての簡単な科学があります。たとえば、同じ値 (初期値は A) に対して CAS 操作を同時に実行する 2 つのスレッドがあります。3 つのスレッドは次のとおりです:

  1. スレッド 1、期待値は A、更新される値は B
  2. スレッド 2、期待値は A、更新される値is B

スレッド 1 が最初に CPU タイム スライスを取得しますが、スレッド 2 は他の理由でブロックされています。スレッド 1 はその値を A の期待値と比較し、等しいことがわかり、値を B に更新します。すると、この時点でスレッド 3 が表示されます。期待値は B で、更新される値は A です。スレッド 3 は、値を期待値 B と比較します。値が等しいことが判明した場合、このとき、スレッド 2 はブロッキングから回復し、CPU タイム スライスを取得します。この値と期待値 A を比較し、等しい場合、値を B に更新します。スレッド 2 も操作を完了しましたが、スレッド 2 は値が A->B->A に変更されたことを知りません。

具体的な例を挙げてください

シャオミンは現金自動預け払い機の問題のため、現金自動預け払い機から50元を引き出しました。 2 つのスレッドがあり、同時に残高を 100 から 50 に変更します。

  • スレッド 1 (現金自動預け払い機): 現在の値 100 を取得し、それを 50 に更新することを期待します。 ;
  • スレッド 2 (現金自動預け払い機): 現在値 100 を取得、50 に更新されることが予想されます;
  • スレッド 1 は正常に実行されました、スレッド 2 は何らかの理由でブロックされています ;
  • この時点で、誰かが Xiao Ming に 50 を送金します;
  • スレッド 3 (デフォルト):現在の値 50 を取得し、それを 100 に更新することを期待します。この時点で、スレッド 3 が正常に実行され、残高は 100 になります。
  • スレッド 2 はブロックから回復し、次の値を取得します。 100。比較後、残高を 50 に更新し続けます。

この時点では、実際の残高は 100 (100-50 50) であるはずですが、実際には 50 (100-50) になっていることがわかります。 50 -50)これは、間違った提出結果をもたらす ABA の問題です。

解決策

ABAの問題を解決するには、バージョン番号を追加できます。 V は変更後、バージョン番号が 1

ずつ増加します。

コード例

AtomicStampedReference による ABA の問題の解決

  • AtomicStampedReference は、オブジェクトの値とバージョン番号を内部的に維持します。AtomicStampedReference オブジェクトを作成するときは、初期値と初期バージョン番号を渡す必要があります。

  • AtomicStampedReference がオブジェクト値を設定する場合、書き込みが成功するには、オブジェクト値とステータス スタンプの両方が期待値を満たしている必要があります。

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. 初期値 100、初期バージョン番号 1
2. スレッド t1 と t2 は同じ初期バージョン番号
3 を取得します。 t1 は ABA 操作を完了し、バージョン番号は 3 に増加しました
4. スレッド t2 は CAS 操作を完了し、最新のバージョン番号は 3 になりました。これは、スレッド t2 が以前に取得したバージョン番号 1 と等しくありません。操作は失敗しました

実行結果:#

t1拿到的初始版本号:1
t2拿到的初始版本号:1
最新版本号:3
false 当前值:100
ログイン後にコピー

#AtomicMarkableReference を通じて ABA 問題を解決する

AtomicStampedReference

バージョン番号をリファレンスに追加し、A -> B -> C -> D などのリファレンスの変更プロセス全体を追跡できます。 -> A. AtomicStampedReference を通じて、プロセス中に 3 回変更された参照変数を知ることができます。ただし、場合によっては、参照変数が何回変更されたかではなく、単に変更されたかどうかだけを気にすることがあります。したがって、AtomicMarkableReference があります。 AtomicMarkableReference の唯一の違いは、参照を識別するために int を使用しなくなり、参照変数が変更されたかどうかを示すためにブール変数を使用することです。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>private static AtomicMarkableReference&lt;Integer&gt; atomicMarkableReference = new AtomicMarkableReference&lt;Integer&gt;(100,false); public static void main(String[] args) { // 第一个线程 new Thread(() -&gt; { System.out.println(&quot;t1版本号是否被更改:&quot; + atomicMarkableReference.isMarked()); //睡眠1秒,是为了让t2线程也拿到同样的初始版本号 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } atomicMarkableReference.compareAndSet(100, 101,atomicMarkableReference.isMarked(),true); atomicMarkableReference.compareAndSet(101, 100,atomicMarkableReference.isMarked(),true); },&quot;t1&quot;).start(); // 第二个线程 new Thread(() -&gt; { boolean isMarked = atomicMarkableReference.isMarked(); System.out.println(&quot;t2版本号是否被更改:&quot; + isMarked); //睡眠3秒,是为了让t1线程完成ABA操作 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(&quot;是否更改过:&quot; + atomicMarkableReference.isMarked()); System.out.println(atomicMarkableReference.compareAndSet(100, 2019,isMarked,true) + &quot;\t当前值:&quot; + atomicMarkableReference.getReference()); },&quot;t2&quot;).start(); }</pre><div class="contentsignin">ログイン後にコピー</div></div>

1. 初期値は 100 で、初期バージョン番号は変更されていません false
2. スレッド t1 と t2 は同じ初期バージョン番号を持ち、変更されていません false

3. スレッド t1 は ABA 操作を完了し、バージョン番号は true に変更されました
4. スレッド t2 は CAS 操作を完了し、バージョン番号は true に変更されましたが、これは取得したバージョン番号 false と等しくありません以前のスレッド t2 によって操作が失敗しました

結果:

t1版本号是否被更改:false
t2版本号是否被更改:false
是否更改过:true
false 当前值:100
ログイン後にコピー

多说几句

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

以上が面接官は「ABA 問題とは何か知っていますか?」と尋ねます。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

CAS (中央認証サービス) を介した PHP セキュリティ検証の実装 CAS (中央認証サービス) を介した PHP セキュリティ検証の実装 Jul 24, 2023 pm 12:49 PM

CAS (CentralAuthenticationService) による PHP セキュリティ検証 インターネットの急速な発展に伴い、ユーザー権限管理と本人確認の重要性がますます高まっています。 Web アプリケーションを開発する場合、ユーザー データを保護し、不正アクセスを防止することが重要です。この目標を達成するには、PHP セキュリティ検証に CAS (CentralAuthenticationService) を使用します。 CAS

Java CASの概念とは何ですか Java CASの概念とは何ですか May 03, 2023 pm 09:34 PM

1. 複数のスレッドがリソースに対して CAS 操作を同時に実行すると、1 つのスレッドだけが成功しますが、他のスレッドはブロックされず、他のスレッドは操作が失敗したというシグナルを受信するだけであることを説明します。 CAS が実際には楽観的ロックであることがわかります。 2. AtomInteger コードをたどると、最後に sum.misc.Unsafe が呼び出されることがわかります。 Unsafe という名前を見てください。これは、Java のクラスと可視性ルールの適切な穴を悪用する安全でないクラスです。速度を向上させるために、Unsafe は Java のセキュリティ標準にいくつかの妥協を加えています。 publicfinalnativebooleancompareAndSwapInt(Objec

CAS と Java オプティミスティック ロックの使用方法 CAS と Java オプティミスティック ロックの使用方法 May 01, 2023 pm 08:07 PM

CASCASとはCompareAndSwap、つまり比較と交換のことです。なぜ CAS はロックを使用しないのに、同時実行条件下でも安全なデータ操作を保証するのですか? その名前は実際に CAS の原理を非常に直観的に示しています。データを変更する具体的なプロセスは次のとおりです: CAS を使用してデータを操作する場合、データの元の値は現在のターゲット変数の値が、渡された元の値と同じかどうかを比較するメソッドに渡します。それらが同じであれば、ターゲット変数が他のスレッドによって変更されていないことを意味します。ターゲット変数の値を直接変更するだけです。ターゲット変数の値が元の値と異なる場合は、ターゲット変数を証明します。他のスレッドによって変更されています。この CAS の変更は失敗しました。上記のプロセスから、CAS が実際にデータの安全な変更を保証しますが、変更が失敗する場合もあります。

JavaでCASを適用する方法 JavaでCASを適用する方法 Apr 18, 2023 pm 06:37 PM

CAS の説明: CAS (compareandswap)、比較および交換。マルチスレッド並列状況でロックを使用することによって引き起こされるパフォーマンス損失を解決できるメカニズム。CAS 操作には、メモリ位置 (V)、期待される元の値 (A)、および新しい値 (B) の 3 つのオペランドが含まれます。メモリ位置の値が予想される元の値と一致する場合、プロセッサはその位置を新しい値に自動的に更新します。それ以外の場合、プロセッサは何も行いません。スレッドはメイン メモリから num 値を取得し、num に対して操作します。値を書き込むとき、スレッドは取得した最初の num 値とメイン メモリ内の num 値を比較します。それらが等しい場合、変更された値は num になります。それらが等しくない場合、成功するまで比較がループされます。 CAS製

Java ロック同時実行性、ロックフリー同時実行性、および CAS サンプル分析 Java ロック同時実行性、ロックフリー同時実行性、および CAS サンプル分析 May 23, 2023 pm 01:34 PM

ロックされた同時実行性 ほとんどのプログラマ (もちろん、私も基本的にその一人です) にとって、同時プログラミングは、関連するデータ構造にロック (Mutex) を追加することとほぼ同等です。たとえば、同時実行をサポートするスタックが必要な場合、最も簡単な方法は、ロック std::sync::Mutex をシングルスレッド スタックに追加することです。 (Arc は、複数のスレッドがスタックの所有権を持てるようにするために追加されます) usestd::sync::{Mutex,Arc};#[derive(Clone)]structConcurrentStack{inner:Arc,}implConcurrentStack{pubfnnew()-> Self{

実際の面接の質問: 同時に実行される CAS メカニズムについて話してください。 実際の面接の質問: 同時に実行される CAS メカニズムについて話してください。 Jul 26, 2023 pm 03:05 PM

プログラムでは 100 個のスレッドを作成し、各スレッドは共有変数 inc に対して 10,000 回の操作を蓄積しました。同期的に実行された場合、inc の最終値は 1,000,000 になるはずですが、マルチスレッドではプログラムが並行して実行されることがわかります。つまり、異なるスレッドがメイン メモリから同時に同じ値を読み取る可能性があります。

springboot に基づいて CAS クライアントを構築する方法 springboot に基づいて CAS クライアントを構築する方法 May 14, 2023 am 10:46 AM

1. 新しい springboot プロジェクトを作成し、依存関係 org.jasig.cas.clientcas-client-support-springboot3.6.22 を導入し、 @EnableCasClient アノテーション packagecom.codetiler.demo;importorg.jasig.cas.client.boot.configuration を構成します。 EnableCasClient;importorg.springframework.boot.SpringApplication;importorg.spring

面接官は「ABA 問題とは何か知っていますか?」と尋ねます。 面接官は「ABA 問題とは何か知っていますか?」と尋ねます。 Jul 26, 2023 pm 03:09 PM

この問題は、CAS 分野の古典的な ABA 問題の分析に関するもので、実際の業務で遭遇したことがあるかどうかはわかりませんが、これが面接での並行性知識テストの焦点です。この種の問題に遭遇したことがない場合は、上記のコードを自分で実行することをお勧めします。

See all articles