ホームページ  >  記事  >  Java  >  揮発性と同期の違いは何ですか?

揮発性と同期の違いは何ですか?

青灯夜游
青灯夜游オリジナル
2020-11-19 14:42:335409ブラウズ

違い: 1. Volatile ではスレッド ブロックが発生しませんが、synchronized ではスレッド ブロックが発生する可能性があります。 2. Volatile はデータの可視性を保証しますが、アトミック性は保証できませんが、synchronized はアトミック性を保証し、間接的に可視性を保証します。

揮発性と同期の違いは何ですか?

可視性

可視性: 共有変数が設定された後のスレッド ペア変更されると、他のスレッドは変数の変更 (変更) をすぐに確認 (認識) できます。
Java メモリ モデルは、ワーキング メモリ内の変数の変更された値をメイン メモリに同期し、変数を読み取る前にメイン メモリからワーキング メモリに最新の値を更新します。メインメモリ上で可視性を実現します。

アトミシティ (原子性)

アトミック性: すべての実行が完了するか、実行されないかのいずれかで、操作を中断することはできません。
Java メモリ モデルでは、同一スレッド内のすべての操作が上から下へ行われることが保証されていますが、複数のスレッドが並列実行されている場合、その操作の順序性は保証されません。

秩序性

秩序性: このスレッドで観察すると、操作はすべて順序どおりに行われています。別のスレッドを観察すると、スレッドの場合、すべての操作が正常に動作しません。

Java メモリ モデルでは、同じスレッド内のすべての操作が上から下に行われることが保証されていますが、複数のスレッドが並行して実行されている場合、それらの操作の順序性は保証できません。
コンピュータがプログラムを実行するとき、パフォーマンスを向上させるために、コンパイラとプロセッサは 命令を再配置することがよくあります。 命令は、一般に次の 3 つのタイプに分類されます。
揮発性と同期の違いは何ですか?
単一-スレッド環境 プログラムの最終的な実行結果がコードの実行結果と一貫していることを保証します
プロセッサは、順序を変更するときに命令間のデータの依存関係を考慮する必要があります マルチスレッド環境では、スレッドコンパイラの最適化の再配置が存在するため、2 つのスレッドで使用される変数が使用される変数の一貫性を保証できるかどうかは不確実であり、結果は予測できません。まず試験をして、できないことは後からやります。

public void mySort(){
int x = 11; //1
int y = 12; //2
x= x+5; // 3
y = x*x;//4

可能な順序は 1234 2134 1324 です。属性 4 は 1 と 3 より前にあります。データの依存関係のため、不可能です。

# volatile は命令の並べ替えを禁止します。 揮発性と同期の違いは何ですか?

public class ReSortSeqDemo {
    int a = 0;
    boolean flag = false;
    
    public void method01() {
        a = 1;           // flag = true;
                         // ----线程切换----
        flag = true;     // a = 1;
    }

    public void method02() {
        if (flag) {
            a = a + 3;
            System.out.println("a = " + a);
        }
    }

}

2 つのスレッドが同時に実行される場合、スレッド 1 がメソッド 01 を実行し、次に切り替えられたスレッド 2 がメソッド 02 を実行すると、メソッド 01 とメソッド 02 の順序が変更され、異なる結果になります。

#命令ソートを無効にする

volatile は、命令の並べ替えを無効にする最適化を実現し、マルチスレッド環境でのプログラムの乱れの現象を回避します

最初に概念を理解します。メモリ バリア (メモリ バリアとも呼ばれます) は CPU 命令です。これには 2 つの機能があります:

特定の操作の実行順序を保証する

特定のメモリの可視性を確保するいくつかの変数の (揮発性メモリの可視性を実現するためにこの機能を使用します)

コンパイラとすべてのプロセッサは命令の並べ替えの最適化を実行できるため、命令の間にメモリ バリアが挿入されると、コンパイラと CPU に、どの命令もこれを並べ替えることはできないと通知します。メモリ バリア命令。メモリ バリアを挿入することにより、メモリ バリアの前後の最適化の並べ替えが禁止されることを意味します。メモリ バリアのもう 1 つの機能は、さまざまな CPU キャッシュ データを強制的にフラッシュして、CPU 上のどのスレッドでもこれらのデータの最新バージョンを読み取れるようにすることです。


次は、保守的な戦略に基づいて揮発性書き込みによってメモリ バリアが挿入された後に生成される命令シーケンスの概略図です。

以下は、揮発性読み出しによってメモリ バリアが挿入された後に生成される命令シーケンスです。保守的な戦略におけるメモリバリア 概略図:
揮発性と同期の違いは何ですか?

揮発性と同期の違いは何ですか?

スレッドの安全性の保証

作業メモリとメインメモリ間の同期遅延メモリが原因で可視性の問題が発生する synchronzied キーワードまたは volatile キーワードを使用して解決できます。これにより、あるスレッドによって変更された変数を他のスレッドからすぐに参照できるようになります。

命令の再配置によって生じる可視性の問題と順序付けの問題については、

volatile キーワードを使用して解決します。 volatile の別の機能は、命令の並べ替えの最適化を禁止することであるためです。


volatile

変数## 変更します #コピーを保持せず、メイン メモリに直接アクセスします

Java メモリ モデルには、メイン メモリがあり、各スレッドにも独自のメモリ (レジスタなど) があります。パフォーマンスを向上させるために、スレッドはアクセスする変数のコピーを自身のメモリに保持します。このように、あるスレッドのメモリ内の同じ変数の値が、ある時点での別のスレッドのメモリ内の値またはメイン メモリ内の値と一致しない状況が発生します。変数を volatile として宣言すると、変数はいつでも他のスレッドによって変更できるため、スレッド メモリにキャッシュできなくなります。

使用シナリオ

揮発性変数を使用してロックを置き換えることができるのは、限られた状況のみです。揮発性変数が理想的なスレッド セーフを提供するには、次の 2 つの条件が同時に満たされる必要があります。

1)
変数への書き込み操作は現在の値に依存しません。 2) 変数は、他の変数との不変式に含まれません。

volatile は、1 つのスレッドが書き込み、複数のスレッドが読み取りを行う状況に最適です。

複数のスレッドが同時に書き込みを行っている場合でも、代わりにロック、スレッドセーフなコンテナー、またはアトミック変数を使用する必要があります。

synchronized

メソッドまたはコード ブロック

を変更するために使用すると、このコードを同時に実行できるスレッドは最大で 1 つです。

2 つの同時スレッドが同じオブジェクト オブジェクト内の synchronized (this) 同期コード ブロックにアクセスする場合、一度に 1 つのスレッドのみを実行できます。別のスレッドは、このコード ブロックを実行する前に、現在のスレッドがこのコード ブロックの実行を完了するまで待つ必要があります。
  1. ただし、スレッドがオブジェクトの同期された (この) 同期コード ブロックにアクセスするとき、別のスレッドはオブジェクト内の非同期 (この) 同期されたコード ブロックに引き続きアクセスできます。
  2. 特に重要なのは、スレッドがオブジェクトの同期された (この) 同期されたコード ブロックにアクセスすると、オブジェクト内の他のすべての同期された (この) 同期されたコード ブロックへの他のスレッドのアクセスがブロックされることです。
  3. スレッドがオブジェクトの同期された (この) 同期されたコード ブロックにアクセスすると、このオブジェクトのオブジェクト ロックを取得します。その結果、オブジェクト オブジェクトのすべての同期されたコード部分への他のスレッドによる
  4. アクセスは一時的にブロックされます

  5. 共有リソースとオブジェクトが追加、削除、および変更されました。 揮発性と同期の違いは何ですか?
ロック

jdk 5.0 以降、Java はより強力なスレッド同期メカニズムを提供します。同期は、同期ロック オブジェクトを明示的に定義することによって実現され、同期ロックは使用される Lock オブジェクトは次のように機能します。

java.util.concurrent.Locks.Lock インターフェースは、共有リソースへの複数のスレッドのアクセスを制御するツールです。ロックは、共有リソースへの排他的アクセスを提供します。一度に 1 つのスレッドのみが Lock オブジェクトをロックできます。スレッドは、共有リソースへのアクセスを開始する前に Lock オブジェクトを取得する必要があります。

ReentrantLock クラスは、synchronized と同じ同時実行性とメモリ セマンティクスを備えた Lock を実装します。スレッド セーフティ制御を実現するには、ReentrantLock の方が一般的に使用され、ロックの表示とロックの解放ができます。

揮発性と同期の違いは何ですか?

違い

揮発性と同期性

  • volatile は変数修飾子ですが、synchronized はコードまたはメソッド

    に作用します。

  • volatile はスレッド メモリと「メイン」メモリの間で変数の値を同期するだけですが、synchronized はモニタをロックおよびロック解除することですべての変数の値を同期しますが、明らかに synchronized の方が volatile よりも優れています。より多くのリソースを消費します。
  • volatile ではスレッド ブロックが発生しませんが、synchronized ではスレッド ブロックが発生する可能性があります。
  • volatile はデータの可視性を保証しますが、

    はアトミック性を保証できません;一方、synchronized はアトミック性を保証し、間接的に可視性を保証します。プライベート メモリとパブリック メモリのデータを同期します。

  • volatile とマークされた変数はコンパイラによって最適化されませんが、synchronized とマークされた変数はコンパイラによって最適化できます。
  • スレッドの安全性には、原子性と可視性の 2 つの側面が含まれます。Java の同期メカニズムは、スレッドの安全性を確保するために、これら 2 つの側面に重点を置いています。
キーワード volatile は、主に、複数のスレッドがインスタンス変数の変更を検出し、最新の値を取得できる場合、つまり、複数のスレッドが共有変数を読み取るときに、最新の値を取得できる場合に使用されます。


キーワード volatile は、プライベート メモリから変数を読み取るのではなく、毎回共有メモリから変数を読み取るようにスレッドに指示するため、同期されたデータの可視性が確保されます。ただし、インスタンス変数

のデータを変更する場合には注意してください。

例: i、つまり i=i 1 の場合、そのような操作は実際にはアトミック操作ではありません。つまり、スレッドセーフではありません。式 i の演算ステップは次のように分類されます。
1) i の値をメモリから取得します。
2) i の値を計算します;
3) i の値をメモリに書き込みます。
ステップ 2 で値を計算するときに、別のスレッドも i の値を変更すると、この時点でダーティ リード データが name に表示されます。解決策は、synchronized キーワードを使用することです。 つまり、volatile 自体はデータのアトミック性を処理しませんが、データの読み取りと書き込みがタイムリーにメイン メモリに影響を与えるように強制します。

synchronized と Lock

Lock は明示的なロック (手動で開閉します。ロックをオフにすることを忘れないでください)、synchronized は暗黙的なロックです。ロック、範囲外 ロックを自動的に解除します。
Lock はコード ブロックのみをロックし、synchronized はコード ブロックとメソッドに作用します。
Lock ロックを使用すると、jvm はスレッドのスケジュールに費やす時間が短縮され、パフォーマンスが向上します。また、スケーラビリティが向上します (より多くのサブクラスを提供します)。
使用順序: ロック -> 同期されたコード ブロック (メソッド本体に入り、対応するリソースが割り当てられている) -> 同期されたメソッド (メソッド本体の外)。

プログラミング関連の知識をさらに知りたい場合は、プログラミング学習コースをご覧ください。 !

以上が揮発性と同期の違いは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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