インタビューでvolatileキーワードを渡して、スレッドメモリモデルの機能を完全に実証します

    面接中、面接官はしばしばvolatileキーワードを使用して、マルチスレッドでの候補者の能力を評価します。そのような質問がされたら、次の手順を実行してこの能力を完全に理解できます。

    1まず、メモリモデルを通じてvolatileキーワードの役割を説明します

    まず、volatileで変更された変数はメモリの内容を直接変更でき、変更された変数は他のスレッドに表示されることを説明します。次に、説明を次のように展開します。

    複数のスレッドが同じリソースを同時に操作する場合、最終結果は期待される結果と異なる場合があります。この状況は、スレッドの安全性とセキュリティの問題に関連するケースを通じて直感的に確認できます。ここでは、スレッドのメモリ構造を使用します。詳細な分析「一貫性のない最終結果」の原因の。

    スレッドがデータ変数を操作したい場合、スレッドは最初にデータ変数をスレッドの内部メモリにロードしてコピーを作成し、次にスレッドはメインメモリのデータ変数との関係を失いますが、はコピー変数を操作します操作が完了すると、コピーはメインメモリ(つまり、ヒープメモリ)に書き戻されます。このプロセスを次の図に示します。

    データの初期値を0とすると、100個のスレッドが同時に1を加算し、期待される結果は100になります。ただし、実際の操作プロセスでは、AスレッドとBスレッドが同時にデータであり、Aによって読み取られた値が0で、Bによって読み取られた値が1であると想定します。Bがスレッド内部メモリでプラス1の操作を完了すると(データは2になります)、Bはデータをメインメモリに書き戻し、メインメモリのデータも2になります。

    ただし、その後、Aスレッドもプラス1操作を完了しました(この時点でA内部スレッドのデータコピーは1です)。後続のライトバックプロセスで、メインメモリのデータ変数は2からに設定されます。 1、これは一貫性のないデータの問題を引き起こします。

    ただし、データ変数が揮発性変数によって変更された場合、Aスレッドの変更されたデータ変数は、「ライトバック」ステージを待たずにメインメモリに直接書き戻すことができます。 "他のスレッドにすぐに表示されます" "。

2同時に、volatileはデータの不整合の問題を解決できません

変数の前にvolatileが追加された場合、スレッドは変数を使用するたびにメインメモリから変数の最新の値を読み取り、スレッドが変数を変更すると、変更はすぐにメインメモリに書き戻されます。 。

変数の最新の値は、操作の前にメインメモリから読み取られ、変更のたびにメインメモリに書き戻されるので、これにより、複数のスレッドでのデータの不整合の問題を解決できますか?次のVolilateDemo.javaコードを通じて、この質問への回答を確認します。

1	public class VolilateDemo extends Thread {
2		//启动1000个线程,对这个被volatile修饰的变量进行加1操作
3	    public static volatile int cnt = 0;
4		public static void add() {
5			// 延迟1毫秒,增加多线程并发抢占的概率
6			try { Thread.sleep(1);}
7	        catch (InterruptedException e) {	}
8			cnt++;//加操作
9		}
10		public static void main(String[] args) {
11			// 同时启动1000个线程,去进行加操作
12			for (int i = 0; i < 1000; i++) {
13				new Thread(new Runnable() {
14					public void run() 
15	                 {VolilateDemo.add();	}
16				}).start();
17			}
18			System.out.println("Result is " + VolilateDemo.cnt);
19		}
20	}

    main関数の12行目では、forループを介して1000スレッドが開始されています。13行目から16行目まで、Runnableクラスを渡して、スレッドのアクションを定義しました。各スレッドが開始された後、15行目のaddメソッドが呼び出され、volatileで変更されたcnt変数に1が追加されます。

    複数の実行の結果は異なる場合がありますが、ほとんどの場合、cntの最終値は1000未満になります。つまり、volatileで変更された変数は、データの整合性を保証できません。つまり、volatileをロックとして使用することはできません。 。メインメモリ内の変数が同じ期間に1つのスレッドのみによって操作されることを保証できないため。

3次に、揮発性物質の役割について話します

     では、揮発性物質の使用は何ですか?volatileによって変更された変数が使用されるたびに、各スレッドの内部メモリからではなく、メインメモリから取得されます。このようにして、「コピーの作成」から「コピーをメインメモリに書き戻す」などの操作を回避することができ、それによって効率が向上する。

    ただし、マルチスレッド環境で変数の読み取りおよび書き込み操作を行っている場合は、それをvolatileに変更しないでください。データの不整合の問題を解決するために、変数をロックして、変数が1つのスレッドのみになるようにするためです。一定期間で動作できるため、揮発性の利点を利用できません。

    この結論に留意してください。変数がマルチスレッド環境で読み取りまたは書き込み操作のみを行う場合は、変数をvolatileに設定することをお勧めします。これにより、マルチスレッド同時実行の効率が向上します。

4可能であれば、ConcurrentHashMapの基礎となるコードに展開します

    上記の内容を言った後、実際には、あなたはすでにあなたの記憶力を完全に示すことができますが、もう1つ言うことができます:volatileキーワードを使用するConcurrentHashMapの基礎となるソースコードも見ました。

    ConcurrentHashMapは、並行性をサポートするHashMapです。率直に言って、複数のスレッドがConcurrentHashMapオブジェクトを同時に読み書きする場合でも問題はありません。

    このオブジェクトのキーと値のペアを格納するNodeオブジェクトは、次のように定義されます。値を表すval変数は、volatileによって変更されます。つまり、AスレッドによるConcurrentHashMapの操作は、メインに書き戻すことができます。すぐにメモリを使用できるため、他のスレッドもすぐに確認できます。したがって、同時実行をサポートできます。

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    //可以看到这些都用了volatile修饰
    volatile V val;
    volatile Node<K,V> next;

    省略其它代码 
}

    誰もがvolatileキーワードからConcurrentHashmapの基礎となるソースコードに拡張すると、インタビュアーはあなたが非常に経験豊富であることを知るでしょう。比較的大規模なインターネット会社に面接に行ったとき、そのことを言ったのを覚えています。それから、このラウンドの技術面接に合格しました(ただし、後続の部門マネージャーとの技術面接もありました)。

私の公式アカウントに注意してください:一緒に進歩し、一緒にお金を稼ぎましょう。この公式アカウントには、素晴らしいインタビュー記事がたくさんあります。

 

 

 

おすすめ

転載: blog.csdn.net/sxeric/article/details/112915422