volatileキーワードは何に役立ちますか


671

今日の仕事で、私volatileはJavaでキーワードに出くわしました。あまり詳しくないので、次の説明を見つけました。

Javaの理論と実践:ボラティリティの管理

その記事で問題のキーワードを説明している詳細を考えて、それを使用したり、このキーワードを正しい方法で使用できるケースを見たりしたことがありますか?

回答:


741

volatileメモリの可視性に関するセマンティクスがあります。基本的に、volatile書き込み操作が完了した後、フィールドの値はすべてのリーダー(特に他のスレッド)から見えるようになります。がなければvolatile、読者は更新されていない値を確認できます。

あなたの質問に答えるには:はい、volatile変数を使用して、一部のコードがループを継続するかどうかを制御します。ループはvolatile値をテストし、そうであれば続行しますtrue。条件はfalse、 "stop"メソッドを呼び出すことで設定できます。ループはfalse、stopメソッドが実行を完了した後で値をテストするときに確認して終了します。

私が強くお勧めする「Java Concurrency in Practice」という本は、の良い説明ですvolatile。この本は、質問で参照されているIBMの記事を書いたのと同じ人物が書いています(実際、彼はその記事の最後で彼の本を引用しています)。私の使用volatileは、彼の記事が「パターン1ステータスフラグ」と呼んでいるものです。

volatile内部でどのように機能するかについて詳しく知りたい場合は、Javaメモリモデルを参照してください。そのレベルを超えたい場合は、Hennessy&Pattersonなどの優れたコンピューターアーキテクチャブックをチェックして、キャッシュの一貫性と一貫性について読んでください。


118
この答えは正しいですが、不完全です。これは、volatileJSR 133で定義された新しいJavaメモリモデルに付属している重要なプロパティを省略しています。スレッドがvolatile変数を読み取るとき、他のスレッドによって最後に書き込まれた値だけでなく、他の変数への他のすべての書き込みも確認します。volatile書き込み時にその別のスレッドに表示されていました。参照してくださいこの答え、この参照を
アダムZalcman 2013

46
初心者のために、私はあなたにいくつかのコードを使ってデモンストレーションするようにお願いします(どうぞ?)
Hungry Blue Dev

6
質問にリンクされている記事にはコード例があります。
グレッグマット

「ヘネシーとパターソン」のリンクは壊れていると思います。また、「Javaメモリモデル」へのリンクは、実際にはOracleのJava言語仕様「第17章スレッドとロック」につながります。
クリス

2
@fefrei:「すぐに」は口語的な用語です。もちろん、実行タイミングもスレッドスケジューリングアルゴリズムも実際に指定されていない場合は保証されません。プログラムが揮発性の読み取りが特定の揮発性の書き込みの後であるかどうかを確認する唯一の方法は、表示された値が予期された値であるかどうかを確認することです。
Holger 2017

177

「…volatile修飾子は、フィールドを読み取るすべてのスレッドが最後に書き込まれた値を参照することを保証します。」 -Josh Bloch

を使用することを考えている場合は、アトミック動作を扱うvolatileパッケージjava.util.concurrentを読んでください。シングルトンパターン

に関するウィキペディアの投稿では、揮発性の使用が示されています。


18
volatilesynchronizedキーワードの両方があるのはなぜですか?
ptkato

5
シングルトンパターンに関するWikipediaの記事は、それ以来大幅に変更されており、上記のvolatile例をもう取り上げていません。それは見つけることができますアーカイブされたバージョンで
bskp

1
@ptkatoこれら2つのキーワードの目的は完全に異なるため、この質問は比較としてあまり意味がありませんが、どちらも並行性に関連しています。「なぜvoidpublicキーワードの両方があるのですか」と言っているようなものです。
DavidS

134

についての重要なポイントvolatile

  1. Javaキーワードsynchronizedおよびvolatileandロックを使用することにより、Javaでの同期が可能です。
  2. Javaでは、synchronized変数を使用できません。synchronized変数でキーワードを使用することは違法であり、コンパイルエラーになります。synchronizedJavaで変数を使用する代わりに、Java volatile変数を使用できます。これは、JVMスレッドにvolatileメインメモリから変数の値を読み取り、ローカルにキャッシュしないように指示します。
  3. 変数が複数のスレッド間で共有されていない場合は、volatileキーワードを使用する必要はありません。

ソース

の使用例volatile

public class Singleton {
    private static volatile Singleton _instance; // volatile variable
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null)
                    _instance = new Singleton();
            }
        }
        return _instance;
    }
}

最初のリクエストが来たときにインスタンスを遅延して作成しています。

我々は作成しない場合は_instance、変数volatileのインスタンスを作成されたスレッド、その後にSingleton他のスレッドに通信することができません。したがって、スレッドAがシングルトンインスタンスを作成していて、作成直後にCPUが破損するなどの場合、他のすべてのスレッドは_instancenullでないの値を確認できず、nullが割り当てられていると信じます。

なぜこれが起こるのですか?リーダースレッドはロックを行わず、ライタースレッドが同期されたブロックから出るまで、メモリは同期_instanceされず、メインメモリのの値は更新されません。JavaのVolatileキーワードを使用すると、これはJava自体によって処理され、そのような更新はすべてのリーダースレッドで表示されます。

結論volatileキーワードは、スレッド間でメモリの内容を通信するためにも使用されます。

揮発性なしの使用例:

public class Singleton{    
    private static Singleton _instance;   //without volatile variable
    public static Singleton getInstance(){   
          if(_instance == null){  
              synchronized(Singleton.class){  
               if(_instance == null) _instance = new Singleton(); 
      } 
     }   
    return _instance;  
    }

上記のコードはスレッドセーフではありません。JITコンパイラは、同期されたブロック内でインスタンスの値をもう一度チェックしますが(パフォーマンス上の理由から)、コンストラクタが実行を完了する前にインスタンスへの参照が設定されるようにバイトコードを再配置できます。つまり、getInstance()メソッドは、完全に初期化されていない可能性があるオブジェクトを返します。コードをスレッドセーフにするために、インスタンス変数にJava 5以降のキーワードvolatileを使用できます。volatileとマークされた変数は、オブジェクトのコンストラクターがその実行を完全に終了した後でのみ、他のスレッドに表示されます。
ソース

ここに画像の説明を入力してください

volatileJavaでの使用

フェイルファストイテレータは通常volatile、リストオブジェクトのカウンタを使用して実装されます。

  • リストが更新されると、カウンターが増加します。
  • ときにIterator作成され、カウンタの現在の値が中に埋め込まれているIteratorオブジェクト。
  • ときにIterator操作が行われ、方法は、2つのカウンタ値を比較し、スローConcurrentModificationExceptionそれらが異なる場合。

フェイルセーフイテレータの実装は通常、軽量です。それらは通常、特定のリスト実装のデータ構造のプロパティに依存しています。一般的なパターンはありません。


2
「フェイルファストイテレーターは通常、揮発性カウンターを使用して実装されます」-もはやそうではありません。コストがかかりすぎます:bugs.java.com/bugdatabase/view_bug.do?bug_id
Vsevolod Golovanov

_instanceの二重チェックは安全ですか?私はそれらが揮発性でさえ安全ではないと思った
デクスターズ

「JVMスレッドに揮発性変数の値をメインメモリから読み取り、ローカルにキャッシュしないように指示します。」良い点
Humoyun Ahmad

スレッドセーフの場合private static final Singleton _instance;も同様です。
Chris311、2018

52

volatile スレッドを停止するには非常に便利です。

独自のスレッドを作成する必要があるわけではありませんが、Java 1.6には多くの優れたスレッドプールがあります。ただし、スレッドが必要だと確信している場合は、スレッドを停止する方法を知る必要があります。

スレッドに使用するパターンは次のとおりです。

public class Foo extends Thread {

  private volatile boolean close = false;

  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

上記のコードセグメントではclose、whileループで読み取るスレッドは、を呼び出すスレッドとは異なりますclose()。volatileがないと、ループを実行しているスレッドは、変更が終了するのを見ることはありません。

同期の必要がないことに注意してください


2
なぜそれが必要なのかしら。スレッドの同期が危険にさらされるような方法で他のスレッドがこのスレッドのステータス変更に反応する必要がある場合にのみ、それは必要ではありませんか?
Jori

27
@ Jori、whileループでcloseを読み取るスレッドは、close()を呼び出すスレッドとは異なるため、揮発性が必要です。volatileがないと、ループを実行しているスレッドは、変更が終了するのを見ることはありません。
Pyrolistical 2013

そのようなスレッドを停止することと、Thread#interrupt()およびThread#isInterrupted()メソッドを使用することに利点があると思いますか?
Ricardo Belchior

2
@Pyrolistical-スレッドが実際に変更を見たことがないことを確認したか または、この問題を確実にトリガーするように例を拡張できますか?基本的に例と同じであるがvolatileキーワードがないコードを使用した(そして他のユーザーが使用したのを見た)ことを知っているので、私は興味があります。
2016

2
@aroth:今日のJVMでは、実際には、最も単純な例でも、この動作を確実に再現することはできません。より複雑なアプリケーションでは、コード内でメモリの可視性が保証されている他のアクションが実行される場合があります。これは、なぜ機能するかわからないため特に危険であり、コードの単純で明らかに無関係な変更により、アプリケーション...
Holger

31

使用の1つの一般的な例は、スレッドを終了するフラグとして変数volatileを使用することvolatile booleanです。スレッドを開始し、別のスレッドから安全に中断できるようにしたい場合は、スレッドに定期的にフラグをチェックさせることができます。これを停止するには、フラグをtrueに設定します。フラグを作成することによりvolatilesynchronizedブロックを使用する必要なく、それをチェックしているスレッドが次にチェックするときに設定されていることを確認できます。


27

volatileキーワードで宣言された変数は、それを特別にする2つの主要な性質を持っています。

  1. 揮発性変数がある場合、どのスレッドからもコンピュータ(マイクロプロセッサ)のキャッシュメモリにキャッシュすることはできません。アクセスは常にメインメモリから行われました。

  2. ある場合は、書き込み動作 volatile変数に行くと、突然の読み取り操作が要求され、あることが保証され、書き込み動作は、前の読み取り操作に完成となります

上記の2つの特性は、

  • 揮発性変数を読み取るすべてのスレッドは、確実に最新の値を読み取ります。キャッシュされた値はそれを汚染することができないためです。また、読み取り要求は、現在の書き込み操作の完了後にのみ許可されます。

一方で、

  • 私が言及した#2をさらに調査するvolatileと、キーワードは、n個のリーダースレッドとそれにアクセスする1つのライタースレッドのみを持つ共有変数を維持する理想的な方法であることがわかります。volatileキーワードを追加したら完了です。スレッドセーフティに関するその他のオーバーヘッドはありません。

逆に、

私たちはできませんを使用しますvolatile持っている共有変数を満たすために、単にキーワードをそれにアクセスする複数のライター・スレッドを


3
これは、揮発性と同期の違いを説明しています。
ajay

13

longおよびdouble変数型の読み取りおよび書き込み操作の扱いについては誰も言及していません。読み取りと書き込みは、参照変数とほとんどのプリミティブ変数に対するアトミック操作です。ただし、long変数型とdouble変数型は除きます。これらは、volatileキーワードを使用してアトミック操作にする必要があります。@リンク


さらに明確にするために、ブール値の読み取りと書き込みはアトミックであるため、ブール値を揮発性に設定する必要はありません。
Kai Wang

2
@KaiWangは、原子性の目的でブール値にvolatileを使用する必要はありません。しかし、あなたは確かに可視性の理由からかもしれません。それはあなたが言うつもりだったのですか?
SusanW 2017年

12

はい、変更可能な変数に複数のスレッドからアクセスする場合は常にvolatileを使用する必要があります。通常、複数のアトミック操作を実行する必要があるため(たとえば、変数の状態を変更する前に確認するなど)、その代わりに同期ブロックを使用するため、あまり一般的ではありません。


10

私の意見では、volatileキーワードが使用されているスレッドの停止以外の2つの重要なシナリオは次のとおりです。

  1. ダブルチェックのロック機構。シングルトン設計パターンでよく使用されます。この場合、シングルトンオブジェクトはvolatileと宣言する必要があります
  2. スプリアスウェイクアップ。通知呼び出しが発行されていなくても、スレッドが待機呼び出しからウェイクアップすることがあります。この動作はスプリアスウェイクアップと呼ばれます。これは、条件変数(ブールフラグ)を使用して対処できます。フラグがtrueである限り、wait()呼び出しをwhileループに入れます。したがって、Notify / NotifyAll以外の理由でスレッドが待機呼び出しから目覚めた場合、スレッドは遭遇フラグがまだ真であるため、呼び出しは再び待機します。notifyを呼び出す前に、このフラグをtrueに設定してください。この場合、ブールフラグはvolatileとして宣言されます。

#2セクション全体が非常に混乱しているように見えます。これは、失われた通知、偽のウェイクアップ、およびメモリの可視性の問題を混乱させています。また、フラグのすべての使用法が同期している場合、揮発性は冗長です。私はあなたのポイントを理解すると思いますが、偽のウェイクアップは正しい言葉ではありません。どうか明らかにしてください。
Nathan Hughes

5

マルチスレッドアプリケーションを開発している場合は、「volatile」キーワード、または「synchronized」などの同時実行制御ツールと、自由に使用できるテクニックを使用する必要があります。このようなアプリケーションの例はデスクトップアプリです。

アプリケーションサーバー(Tomcat、JBoss AS、Glassfishな​​ど)にデプロイされるアプリケーションを開発している場合は、アプリケーションサーバーによって既に処理されているため、同時実行制御を自分で処理する必要はありません。実際、私がJava EE標準を正しく覚えていれば、サーブレットとEJBでの同時実行制御は禁止されています。これは、それが処理する必要のない「インフラストラクチャ」層の一部だからです。シングルトンオブジェクトを実装する場合にのみ、このようなアプリで同時実行制御を行います。これは、Springのようなフレームワークを使用してコンポーネントを編成した場合でも、すでに対処されています。

したがって、アプリケーションがWebアプリケーションであり、SpringやEJBのようなIoCフレームワークを使用するJava開発のほとんどの場合、「volatile」を使用する必要はありません。


5

volatileすべてのスレッドが、それ自体であっても、増加することを保証するだけです。たとえば、カウンターは変数の同じ面を同時に見ます。同期またはアトミックなどの代わりに使用されるのではなく、読み取りを完全に同期させます。他のJavaキーワードと比較しないでください。以下の例に示すように、揮発性変数の操作もアトミックであり、一度に失敗または成功します。

package io.netty.example.telnet;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

揮発性を入れても入れなくても、結果は常に異なります。ただし、以下のようにAtomicIntegerを使用すると、結果は常に同じになります。これは同期も同じです。

    package io.netty.example.telnet;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }

4

はい、私はそれをかなり頻繁に使用します-マルチスレッドのコードに非常に役立ちます。あなたが指摘した記事は良いものです。ただし、2つの重要な点に注意してください。

  1. volatileの機能と、同期化の違いを完全に理解している場合にのみ、volatileを使用してください。多くの状況で、揮発性は表面上、同期よりも単純で高性能な代替手段であるように見えます。
  2. volatileは、同期されていても、実際には多くの古いJVMでは機能しません。さまざまなJVMでさまざまなレベルのサポートを参照しているドキュメントを見たのを覚えていますが、残念ながら今は見つかりません。Java 1.5より前のバージョンを使用している場合、またはプログラムが実行されるJVMを制御できない場合は、確実に調べてください。

4

揮発性フィールドにアクセスするすべてのスレッドは、(潜在的に)キャッシュされた値を使用する代わりに、続行する前に現在の値を読み取ります。

メンバー変数のみが揮発性または一時的です。


3

もちろん。(そしてJavaだけでなく、C#でも。)特定のプラットフォーム(たとえば、intまたはboolean)でアトミック操作であることが保証されているが、必要としない値を取得または設定する必要がある場合があります。スレッドロックのオーバーヘッド。volatileキーワードを使用すると、値を読み取るときに確実に現在の値を取得できます。値別のスレッドでの書き込みによって廃止されたばかりのキャッシュされた値ではない。


3

volatileキーワードの使用法は2つあります。

  1. JVMがレジスターから値を読み取らないようにし(キャッシュと想定)、その値を強制的にメモリーから読み取ります。
  2. メモリの不整合エラーのリスクを軽減します。

JVMがレジスターの値を読み取らないようにし、その値を強制的にメモリーから読み取ります。

ビジーフラグは、デバイスがビジー状態であるとフラグをロックによって保護されていない状態の継続からスレッドを防止するために使用されます。

while (busy) {
    /* do something else */
}

別のスレッドがオフになると、テストスレッドが継続されます忙しいフラグ

busy = 0;

ただし、ビジーはテストスレッドで頻繁にアクセスされるため、JVMはビジーの値をレジスタに配置してテストを最適化し、テストの前にメモリのビジーの値を読み取らずにレジスタの内容をテストします。テストスレッドはビジー状態の変更を認識せず、他のスレッドはメモリ内のビジー状態の値のみを変更するため、デッドロックが発生します。busyフラグをvolatileとして宣言すると、各テストの前にその値が読み取られます。

メモリの一貫性エラーのリスクを軽減します。

揮発性変数への書き込みは、同じ変数の後続の読み取りと「前に発生」の関係を確立するため 、揮発性変数を使用すると、メモリ整合性エラーのリスクが軽減されます。これは、揮発性変数への変更は常に他のスレッドから見えることを意味します。

メモリの一貫性エラーなしで読み取り、書き込みを行う手法は、アトミックアクションと呼ばれます。ます。

アトミックアクションは、一度に効果的に発生するアクションです。アトミックアクションは途中で停止することはできません。完全に発生するか、まったく発生しません。アトミックアクションの副作用は、アクションが完了するまで表示されません。

以下は、アトミックであると指定できるアクションです。

  • 読み取りと書き込みは、参照変数とほとんどのプリミティブ変数(longとdoubleを除くすべての型)に対してアトミックです。
  • 読み取りと書き込みは、揮発性と宣言されたすべての変数 (longおよびdouble変数を含む)に対してアトミックです。

乾杯!


2

揮発性は以下を行います。

1>異なるスレッドによる揮発性変数の読み取りおよび書き込みは、スレッド自体のキャッシュまたはCPUレジスタからではなく、常にメモリから行われます。したがって、各スレッドは常に最新の値を扱います。2> 2つの異なるスレッドがヒープ内の同じインスタンスまたは静的変数を処理する場合、他のアクションが順不同に見える場合があります。これに関するジェレミー・マンソンのブログを見てください。しかし、揮発性はここで役立ちます。

以下の完全に実行中のコードは、同期キーワードを使用せずに、いくつかのスレッドが事前定義された順序で実行し、出力を印刷する方法を示しています。

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

これを達成するために、以下の本格的な実行コードを使用できます。

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

次のgithubリンクには、適切な説明が記載されているreadmeがあります。 https://github.com/sankar4git/volatile_thread_ordering


2

volatileプログラマーにとって、値は常に最新であると言います。問題は、値がさまざまな種類のハードウェアメモリに保存できることです。たとえば、CPUレジスタ、CPUキャッシュ、RAMなどです。СPUレジスタとCPUキャッシュはCPUに属し、マルチスレッド環境で救済されているRAMとは異なり、データを共有できません。

ここに画像の説明を入力してください

volatileキーワードは、変数がRAMメモリに直接読み書きされることを示します。いくつかの計算フットプリントがあります

Java 5volatileサポートについて拡張happens-before[概要]

揮発性フィールドへの書き込みは、そのフィールドの後続のすべての読み取りの前に行われます。

volatileキーワードは硬化しないrace conditionいくつかのスレッドができる状況書き同時にいくつかの値を。答えはsynchronizedキーワードです

その結果、1つのスレッドが書き込みを行い、他のスレッドvolatile値を読み取る場合にのみ安全です。

揮発性と同期


1

Oracleのドキュメントページから、メモリの一貫性の問題を修正するために、揮発性変数の必要性が生じています。

揮発性変数を使用すると、揮発性変数への書き込みにより、同じ変数の後続の読み取りとの発生前の関係が確立されるため、メモリ整合性エラーのリスクが軽減されます。

これは、volatile変数への変更が他のスレッドから常に見えることを意味します。また、スレッドが揮発性変数を読み取るときに、最新の変更だけではなく、volatileもたらしたコードの副作用ます。

で説明されているように Peter Parker回答で、volatile修飾子がない場合、各スレッドのスタックは独自の変数のコピーを持つことができます。変数をvolatile、メモリの一貫性の問題が修正されました。

ジェンコフを見てくださいよりよく理解するためにチュートリアルページをください。

揮発性と揮発性を使用する使用例の詳細については、関連するSEの質問を参照してください。

Javaでの揮発性と同期の違い

1つの実用的な使用例:

たとえば、現在の時刻を特定の形式で出力する必要があるスレッドが多数ありますjava.text.SimpleDateFormat("HH-mm-ss")。Yonは1つのクラスを持つことができ、現在の時刻をSimpleDateFormat1秒ごとに変数に変換して更新します。他のすべてのスレッドは、この揮発性変数を使用して、現在の時刻をログファイルに出力できます。


1

揮発性変数は軽量の同期です。すべてのスレッド間で最新データの可視性が必要であり、原子性が損なわれる可能性がある場合、そのような状況では揮発性変数を優先する必要があります。揮発性変数の読み取りは、レジスタや他のプロセッサが認識できないキャッシュにはキャッシュされないため、常にスレッドによって行われた最新の書き込みを返します。揮発性はロックフリーです。シナリオが上記の基準を満たす場合、私は揮発性を使用します。


-1

揮発性キーを変数と共に使用すると、この変数を読み取るスレッドが同じ値を確実に参照できるようになります。変数の読み取りと書き込みを行う複数のスレッドがある場合、変数を揮発性にするだけでは不十分で、データが破損します。イメージスレッドは同じ値を読み取りましたが、それぞれがいくつかの変更を加えました(たとえば、カウンターをインクリメントしました)。メモリに書き戻すと、データの整合性が損なわれます。そのため、変数を同期させる必要があります(異なる方法が可能です)。

変更が1つのスレッドによって行われ、他のスレッドがこの値を読み取るだけでよい場合は、volatileが適しています。


-1

volatile変数は基本的に、更新後のメイン共有キャッシュラインでの即時更新(フラッシュ)に使用されるため、変更はすべてのワーカースレッドにすぐに反映されます。


-2

以下は、volatile他のスレッドからのスレッド実行を制御するために使用されるfor変数の要件を示す非常に単純なコードです(これは、volatile必要なシナリオの1つです)。

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

ときにvolatile使用されていない:あなたは「見ることは決してないだろう:XXXで停止しても」の後のメッセージ「に停止:XXX」、およびプログラムが実行を継続します。

Stopping on: 1895303906650500

volatile使用時:Stopped on:xxx」がすぐに表示されます。

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

デモ:https : //repl.it/repls/SilverAgonizingObjectcode


反対票を投じる:反対票を投じる理由を説明してください。これが真実でなければ、少なくとも私は何が悪いのかを学ぶでしょう。私はこの同じコメントを2回追加しましたが、誰が何度も削除しているのかわかりません
manikanta

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.