揮発性キーワードのJava詳細説明

揮発性の紹介

揮発性の概要

  1. volatileは比synchronizedキーワード更轻量级同步机制あり、volatile変数にアクセスする加锁操作が実行されるため、実行され线程阻塞ます。
  2. 揮発性の保証可见性禁止指令重排序、底部を通って「です内存屏障達成するために」、しかし不保证原子性
  3. 写入揮発性の変数は以下と等価である退出同步代码块读取揮発性変数と同等进入同步代码块

揮発性の使用シナリオ

  1. 変数の入力操作により、変数の値を不依赖变量的当前值確認でき只有单个线程更新ます。
  2. 変数不会与其他状态变量一起纳入不变性条件中;(変数は他の変数の不変条件には含まれません)
  3. 変数にアクセスするとき不需要加锁

ユースケース

  1. 状态标记量:ステータスフラグに従って、スレッドを終了します。つまり、特定のステータスフラグをチェックしてループを終了するかどうかを決定するシナリオでは、volatileを使用できます。
  2. 单例模式中的double checkinstance = new Singleton()このコード行はアトミック操作ではないためインスタンスを揮発的に変更し、インスタンスにメモリを割り当て、シングルトンのコンストラクターを呼び出してメンバー変数を初期化し、インスタンスオブジェクトを割り当てられたメモリ空間にポイントします。

揮発性変数の定義に関するJMMの特別なルール:

  1. 他のスレッドによる変数の変更を確実に確認できるように、現在のスレッドを毎回使用する使用变量前都必要があります先从主内存刷新最新的值read、load、use连续执行メモリからメモリへ工作。)
  2. 現在修改变量后立刻同步他のスレッドがスレッドへの変更を確認できるように、毎回メインメモリにアクセスする必要があります。メモリassign、store、writeから工作メモリへの連続実行。)
  3. volatileによって変更された変数不会被指令重排序优化は、コードの実行順序がプログラムの順序と同じであることを保証します。

命令の順序変更の最適化を禁止する可視性と原則

(基になるロック命令によって実現)
  volatileはスレッドの可視性を保証し、特定の順序を提供できますが、原子性は保証できません。volatileはJVMの下部にある「内存屏障で実装されます。セマンティクスの2つの層:保证可见性,不保证原子性; 禁止指令重排序

可視性

すべてのスレッドに対して   揮発性変数の可視性を確保ます可視性とは、スレッドがこの変数の値を変更すると、新しい値が他のスレッドにすぐに認識されることを意味します。通常の変数は許可されていません。スレッド間の共通変数の値の転送は、メインメモリを通じて行う必要があります。たとえば、スレッドAは通常の変数の値を変更してメインメモリに書き戻します。別のスレッドBは、スレッドAが書き込みを完了した後に書き戻しますメインメモリから読み取った後にのみ、新しい変数値がスレッドBに表示されます。
  揮発性の基盤となることにより、ロックの接頭辞、そう効果という存在キャッシュCPUのメモリに書き込まれ、書き込み動作が発生します別のCPUまたはその他のコアのキャッシュの無効化、キャッシュJMM変数と同等であった「ストアと書き込みを「操作、このスレッドは他のスレッドの変数のキャッシュラインを無効します他のスレッドが変数を読み取り、変数のキャッシュラインが無効あることを検出する必要がある場合、データはメインメモリから再ロードされるため、データの可視性が保証されます。揮発性変数を
  書き込むことは、同期コードブロック終了することと同等であり、揮発性変数読み取ることは、同期コードブロック入力することと同等です。ロック機構は可視性と原子性の両方を保証できますが、揮発性変数は可視性のみを保証し、原子性は保証しません

命令の並べ替えの最適化を禁止する

  変数がvolatileとして宣言されると、コンパイラーとランタイムは変数がsharedであることを認識します。これは、変数に対する操作が他のメモリー操作並べ替えられ、volatile変数がレジスターまたはその他にキャッシュされないためです。プロセッサーが見えない場所。
  volatileによって変更された変数は、アセンブリコードで追加のロック操作実行します。これは、メモリバリア(メモリバリア、つまり並べ替え時に後続の命令をメモリバリアの前の位置並べ替えることができない)と同等です。
  1つのCPUのみがメモリにアクセスする場合、メモリバリアは必要ありませんが、複数のCPUが同じメモリにアクセスし、そのうちの1つが他のCPUを監視している場合、一貫性を確保するためにメモリバリアが必要です。ロック命令がメモリへの変更を同期化する場合、それは以前のすべての操作が実行されたことを意味し、命令の並べ替えがメモリバリアを越えることができないという感覚を形成する可能性があります。
命令の順序変更を禁止する揮発性の原則:
ここに画像の説明を挿入

  1. とき第二个操作是volatile写の時間は、何の最初の操作が何であるかは関係ありません都不能重排序このルールにより、揮発性書き込み前の操作が、揮発性書き込み後にコンパイラによって並べ替えられなくなります。
  2. とき第一个操作是volatile读の時間は、何の2番目のアクションが何であるかは関係ありません都不能重排序このルールは、揮発性読み取り後の操作が、揮発性読み取り前にコンパイラーによって再順序付けされないようにします。
  3. ときは第一个操作是volatile写第二个操作是volatile读する場合、不能重排序

質疑応答

as-if-serialセマンティクスが制御の依存関係を持つ操作の並べ替えを許可する理由は何ですか?

  シングルスレッドプログラムでは、制御依存関係のある操作の順序を変更しても実行結果は変わりませんが、マルチスレッドプログラムでは、制御依存関係のある操作の順序を変更してもプログラムの実行結果が変わる可能性があります。

発生前の原則は何ですか?

  1. コードルールの順次実行:同じスレッド内で、前の操作が後続の操作の前に発生します。
  2. ロック解除ルールを追加:モニターでの解锁操作は、その後の加锁操作の前に行われます。
  3. 揮発性ルールvolatile変数の操作後続の操作の前に発生します。
  4. スレッド起動ルール:スレッドstart()メソッドは、スレッドの後続のすべての操作の前に発生します。
  5. スレッドには、ルールを終了:すべての操作が起こる-前に、そのスレッドに別のスレッドの呼び出しスレッドjoin()操作の成功後に返します。
  6. スレッド割り込み規則:スレッドinterrupt()メソッドの呼び出しは、割り込みコードが割り込みイベントの発生を検出する前に発生し、Thread.interrupted()メソッドは割り込みが発生したかどうかを検出できます。
  7. オブジェクト終了規則对象的初始化完成発生前のfinalize()メソッドの開始(コンストラクターの実行の終了)
  8. 推移性:bの前に発生する場合、cの前に発生する場合、cの前に発生する場合。

ロックと揮発性の違いは何ですか?

類似点揮発性変数の
  書き込みは同期コードブロックの終了と同等であり、揮発性変数の読み取りは同期コードブロックの入力と同等です。
相違点:
  ロックメカニズム可視性原子性の両方を保証できますが、揮発性変数は可視性のみを保証し原子性は保証しません

通常の変数と揮発性変数の違いは何ですか?

  volatile特別なルール保证新值能立即同步主内存、各使用前すぐにできます从主内存刷新したがって、volatileは多线程操作可见性変数保証できます普通变量不保证

  1. 揮発性の変更された変数は「可視性」を保証できます。スレッドがこの変数の値を変更すると、新しい値はすぐに他のスレッドに認識されます。
  2. 通常の変数は「可視性」を保証できません。スレッド間で共通変数の値を転送するには、メインメモリを完了する必要があります。スレッドAは共通変数の値を変更し、最初にロックしてメインメモリから読み取り、次にメインメモリに書き戻します(ロック、読み取り、読み込み、使用、割り当て、保存、書き込み、ロック解除)。スレッドAのライトバックが完了(ロック解除)された後、別のスレッドBがメインメモリから最新の値(ロック、読み取り、ロード、使用、ロック解除)を読み取り、新しい変数値がスレッドBに表示されます。

原子性の意味論的意味は何ですか?

volatile不保证原子性、しかし、アトミックセマンティクスについて話します。
:1)原子に定義される
操作または操作の、すなわち複数要么全部执行と実行过程不会任意の因子によって打断要么都不执行
2)例:

i = 2;          
i = j ;           
i++;           
i = j + 2;

Javaでは、変数と割り当て動作の基本的なデータタイプがアトミック操作であることを保証するために(それが32ビットJDK環境にある場合動作、ハイとローとに分割される。)アトミック手順全体として、単一スレッドのおそれセクシュアリティですが、マルチスレッドでは、同期とロックによって原子性を確保する必要があります。この操作は、基本データタイプ2をiに割り当てることのみに関与します; i = j、yes 、最初にjの値を取り、次にjの値をiに割り当てます; i ++、yes 、最初にiの値を取り、次にiの値をインクリメントします、最後に、増分した結果をi、yesに割り当てます; i = j + 2、yes 、最初にjの値を取り、次にj + 2を取り、最後にj + 2の結果をi、yesに割り当てますlong和double64位数据读取不是原子两次32位操作
i = 2原子的
两个操作非原子操作
三个操作非原子操作
三个操作非原子操作

JDK1.5以前は、JavaがDCL(ダブルロック検出)を安全に使用してシングルトンモードを実装できないのはなぜですか?

  揮発性マスキング命令の並べ替えのセマンティクスは、JDK1.5では完全に修正されていませんでした。
1)DCLシングルトンモード

public class Singleton {

	// volatile修饰变量
	private volatile static Singleton instance;
	
	private Singleton(){}
	
	// 单例方法
	public static Singleton getInstance(){
		if(instance == null){
			// 加锁synchronized代码块
			synchronized (Singleton.class){
				if(instance == null){
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
	public static void main(String[] args) {
		Singleton.getInstance();
	}    
}

2)静的内部クラスを使用してより安全なメカニズムを実装する

/* 静态内部类 */
public class SingletonInner { 

    // 静态内部类
	private static class Holder { 
		private static SingletonInner singleton = new SingletonInner();
	 } 
	 
	private SingletonInner(){} 
	
	public static SingletonInner getSingleton(){ 
		return Holder.singleton; 
	}
 }
公開された118の元の記事 150のような 訪問40,000+

おすすめ

転載: blog.csdn.net/Andya_net/article/details/105566755