2.3.4非原子の特性

2443 ワード

キーワードvolatileは、インスタンス変数の複数のスレッド間の可視性を増加させるが、同期性を備えず、原子性を備えない.
/**
 * MyThread 
 * @author wuyoushan
 * @date 2017/3/21.
 */
public class MyThread extends Thread {

    volatile public static int count;

    private static void addCount(){
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println("count="+count);
    }

    @Override
    public void run() {
       addCount();
    }
}

/**
 * @author wuyoushan
 * @date 2017/3/20.
 */
public class Run {
    public static void main(String[] args){
        MyThread[] mythreadArray=new MyThread[100];
        for (int i = 0; i < 100; i++) {
            mythreadArray[i]=new MyThread();
        }
        for (int i = 0; i < 100; i++) {
            mythreadArray[i].start();
        }
    }
}

プログラムの実行結果は次のとおりです.
count=3400
count=3500
count=3600
count=9900
count=9900
count=9900

カスタムスレッドクラスを変更します.JAvaファイルは次のとおりです.
/**
 * MyThread 
 * @author wuyoushan
 * @date 2017/3/21.
 */
public class MyThread extends Thread {

    volatile public static int count;

    // static 
    // synchronized static MyThread.class 
    // static , , 
    // 
    synchronized private static void addCount(){
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println("count="+count);
    }

    @Override
    public void run() {
       addCount();
    }
}


プログラムの実行効果は次のとおりです.
count=9600
count=9700
count=9800
count=9900
count=10000

上記のコードではprivate static void addCount()を使用する前にsynchronized同期キーワードを追加すると、volatileキーワードを使用してcount変数を宣言する必要はありません.
キーワードvolatileの主な使用場面は、複数のスレッドでインスタンス変数が変更されたことを感知し、最新の値を得ることができます.つまり、共有変数をマルチスレッドで読み出すことで、最新の値を得ることができます.
キーワードvolatileプロンプトスレッドは、あるメモリからではなく共有メモリから変数を読み出すたびに、同期データの可視性を保証します.しかし、ここで注意すべきは、i+、すなわちi=i+1のようなインスタンス変数のデータを変更すると、このような動作は原子操作ではないことである.つまり、非スレッドは安全です.式i++の操作手順は次のように分解されます.
  • メモリからiの値
  • を取り出す.
  • i計算iの値
  • iの値をメモリに
  • と書きます.
    2ステップ目に値を計算するときに、別のスレッドもiの値を変更すると、このとき汚れたデータが表示されます.解決策はsynchronizedキーワードを用いることであり,この知識点は前述の例で紹介した.だからvolatile自体はデータの原子性を処理するのではなく、データの読み書きを強制してメインメモリにタイムリーに影響を与える.
    volatileで修飾された変数の場合、JVM仮想マシンは、プライマリメモリからスレッドワークメモリにロードされた値が最新であることを保証するだけです.volatileキーワードは、変数の読み取り時の可視性の問題を解決しますが、原子性を保証することはできません.複数のスレッドで同じインスタンス変数にアクセスするには、同期をロックする必要があります.
    Javaマルチスレッドコアプログラミング技術から抜粋-2.3.4