11

知っています

volatile と宣言されたすべての変数の読み取りと書き込みはアトミックです

質問1:これは次のように理解できますか

private volatile int x = 0;

x++;操作はアトミックですか?

そしてそれ

変数 volatile をマークしても、アトミック アクションを同期する必要がすべてなくなるわけではありません。これは、メモリの一貫性エラーが引き続き発生する可能性があるためです。

質問 2:volatileマークされた変数が表示され、同期とマークされたブロックのメソッドが表示されない (変数へのアクセス/変更を試みる) 可能性があるのは、どのような状況 (存在する場合) でしょうか?

つまり、同時変更から保護する必要があるすべての変数をマークする必要がありますvolatileか?

4

3 に答える 3

13

volatileは、追加の可視性の保証、long / doubleのアトミック書き込み/読み取り(それ以外の場合はJLSによって保証されません、はい)、およびいくつかのメモリ順序の保証のみを提供します。同期なし(ただし、揮発性で始まる同期ブロックを構築することは可能です-デッカーのアルゴリズム)したがって、それは役に立ちませんx++-それはまだ読み取り、インク、書き込みであり、何らかの形式の同期が必要です。

volatileの1つの例は、有名なダブルチェックロックです。ここでは、順序の保証が必要なすべてであるため、ほとんどの場合同期を回避します。

private volatile Helper helper = null;
public Helper getHelper() {
    if (helper == null) {
        synchronized(this) {
            if (helper == null) {
                helper = new Helper();
            }
        }
    }
    return helper;
}

同期がまったく含まれない例は、単純な終了フラグです。ここでは、保証の順序付けではなく、保証された可視性についてのみ説明します。

public volatile boolean exit = false;
public void run() {
   while (!exit) doStuff();
   // exit when exit set to true
}

別のスレッドがwhileループを実行している他のスレッドを設定exit = trueした場合、更新を確認することが保証されます。揮発性がないと、更新が表示されない場合があります。

于 2012-07-08T19:06:13.503 に答える
7

x ++; 操作はアトミックですか?

いいえ。これはに減少しx = x + 1ます。の読み取りxはアトミックであり、書き込みxはアトミックですがx = x + 1、全体としてはアトミックではありません。

どのような状況(もしあれば)で、揮発性とマークされた変数を表示し、同期とマークされたブロックのメソッド(変数にアクセス/変更しようとする)を表示できないのではないかと思いますか?

さて、を使用しない並行性へのあらゆる種類のアプローチがありますsynchronized。Javaには他にもさまざまなロックユーティリティがあり、「魔法の」アトミックを多用していますが、volatile:などを必要とするロックフリーアルゴリズムは特定の例です。ConcurrentLinkedQueuecompareAndSet

于 2012-07-08T19:05:22.023 に答える
0

前の回答を説明するための簡単にテストできる例として、これは常に 8 の最終カウントをもたらします。

import java.util.concurrent.atomic.AtomicInteger;


public class ThreadTest_synchronize {

public static void main(String[] args) {

    ThreadTest_synchronize tt = new ThreadTest_synchronize ();
    try {
        tt.go();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

private void go() throws InterruptedException{

    MyRunnable t = new MyRunnable();
    Thread myThread_1 = new Thread( t, "t1");
    Thread myThread_2 = new Thread( t, "t2");
    myThread_1.start();
    myThread_2.start();
    myThread_1.join();
    myThread_2.join();
    System.out.println("Processing count="+t.getCount());       

}

private class MyRunnable implements Runnable{

    private AtomicInteger count=new AtomicInteger(0);

    @Override
    public  void run() {
        for(int i=1; i< 5; i++){
            doSomething(i);
            count.getAndAdd(1);
        }           
    }


    public AtomicInteger getCount() {
        return this.count;
    }


    private void doSomething(int i) {
        try {
            Thread.sleep(i*300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}       

}

これは一般的にはしません:

public class ThreadTest_volatile {

public static void main(String[] args) {

    ThreadTest_volatile tt = new ThreadTest_volatile ();
    try {
        tt.go();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

private void go() throws InterruptedException{

    MyRunnable t = new MyRunnable();
    Thread myThread_1 = new Thread( t, "t1");
    Thread myThread_2 = new Thread( t, "t2");
    myThread_1.start();
    myThread_2.start();
    myThread_1.join();
    myThread_2.join();
    System.out.println("Processing count="+t.getCount());       

}

private class MyRunnable implements Runnable{

    private volatile int count = 0;


    @Override
    public  void run() {
        for(int i=1; i< 5; i++){
            doSomething(i);
            count++;
        }

    }

    private  int add(int count){
        return ++count;
    }


    public int getCount(){
        return count;
    }

    private void doSomething(int i) {

        try {
            Thread.sleep(i*300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


}
于 2013-12-06T12:16:00.883 に答える