741

volatile今日の仕事で、Javaのキーワードに出くわしました。よくわからないので、この説明を見つけました。

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

4

24 に答える 24

811

volatileメモリの可視性のためのセマンティクスがあります。基本的に、volatile書き込み操作が完了すると、フィールドの値はすべてのリーダー (特に他のスレッド) に表示されます。がないvolatileと、読者は更新されていない値を見ることができます。

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

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

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

于 2008-09-20T02:09:51.007 に答える
198
于 2008-09-20T00:59:28.337 に答える
61

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 がないと、ループを実行しているスレッドは、閉じる変更を認識しない可能性があります。

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

于 2008-09-24T22:29:39.607 に答える
31

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

于 2008-09-20T04:00:01.493 に答える
14

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

于 2008-09-20T04:26:30.790 に答える
14

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

于 2015-02-11T14:51:29.300 に答える
11

揮発性

volatilesynchronized【概要】

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

ここに画像の説明を入力

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

Java 5[概要]volatileをサポートすることで拡張happens-before

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

Read is after write

volatileキーワードは、複数のスレッドがいくつかの値を同時に書き込むことができる状況を解決しません。答えはキーワード【About】race conditionsynchronized

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

于 2019-12-27T09:21:13.467 に答える
10

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

  1. ダブルチェックのロック機構。Singleton 設計パターンでよく使用されます。この場合、シングルトン オブジェクトを volatile と宣言する必要があります
  2. スプリアスウェイクアップ。通知呼び出しが発行されていない場合でも、スレッドが待機呼び出しから起床することがあります。この動作は、スプリアス ウェイクアップと呼ばれます。これは、条件変数 (ブール値フラグ) を使用して対抗できます。フラグが true である限り、wait() 呼び出しを while ループに入れます。そのため、スレッドが Notify/NotifyAll 以外の理由で待機呼び出しから復帰した場合、フラグがまだ true であることが検出されるため、待機呼び出しが再度発生します。notify を呼び出す前に、このフラグを true に設定してください。この場合、ブール フラグは volatile として宣言されます。
于 2014-02-25T09:17:27.940 に答える
5

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

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);
        }
    }
}

volatile を入れても入れなくても、結果は常に異なります。ただし、以下のように 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);
            }
        }
    }
于 2013-03-02T21:07:43.430 に答える
5

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

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

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

于 2008-09-20T07:14:12.913 に答える
4

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

  1. volatile が何をするか、およびsynchronized とどのように異なるかを完全に理解している場合にのみ、volatile を使用してください。多くの場合、volatile は、表面的には、synchronized に代わるより単純でパフォーマンスの高い代替手段のように見えますが、多くの場合、volatile をよりよく理解すると、synchronized が機能する唯一のオプションであることが明らかになります。
  2. volatile は実際には多くの古い JVM では機能しませんが、synchronized は機能します。さまざまな JVM のさまざまなレベルのサポートを参照したドキュメントを見たことを覚えていますが、残念ながら今は見つかりません。Java pre 1.5 を使用している場合、またはプログラムが実行される JVM を制御できない場合は、必ず調べてください。
于 2008-09-20T11:07:48.237 に答える
4

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

メンバー変数のみが揮発性または一時的になることができます。

于 2014-08-11T16:27:12.843 に答える
3

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

于 2008-09-20T01:59:35.823 に答える
1

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

于 2016-07-08T11:08:17.810 に答える
-1

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

// 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を使用しない場合: ' Stopping on: xxx ' の後でも ' Stopped on: xxx ' メッセージが表示されることはなく、プログラムは引き続き実行されます。

Stopping on: 1895303906650500

volatile使用すると、' Stopped on: xxx ' がすぐに表示されます。

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

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

于 2019-02-14T05:48:05.610 に答える