目次
1. Volatile 関数
1.1 メモリ可視性の問題
1.2 命令の並べ替えの防止
2. なぜ volatile を使用するのでしょうか?
ホームページ Java &#&チュートリアル Java シングルトン モードに volatile キーワードを追加する必要があるのはなぜですか?

Java シングルトン モードに volatile キーワードを追加する必要があるのはなぜですか?

Apr 19, 2023 pm 02:40 PM
java volatile

    前書き:

    シングルトン モードを実装するには、ハングリー モード、レイジー モード、静的内部クラス、列挙型など、インタビュアーが「なぜ volatile をシングルトン モードに追加する必要があるのですか?」と尋ねたとき、彼はなぜ Lazy モードのプライベート変数を volatile に追加する必要があるのか​​について言及しています。

    遅延モードとは、オブジェクト作成の遅延読み込み方式を指し、オブジェクトはプログラムの起動時には作成されず、実際に初めて使用されるときにのみ作成されます。

    なぜ volatile を追加する必要があるのか​​説明していただけますか?まず、遅延モードの具体的な実装コードを見てみましょう:

    public class Singleton {
        // 1.防止外部直接 new 对象破坏单例模式
        private Singleton() {}
        // 2.通过私有变量保存单例对象【添加了 volatile 修饰】
        private static volatile Singleton instance = null;
        // 3.提供公共获取单例对象的方法
        public static Singleton getInstance() {
            if (instance == null) { // 第 1 次效验
                synchronized (Singleton.class) {
                    if (instance == null) { // 第 2 次效验
                        instance = new Singleton(); 
                    }
                }
            }
            return instance;
        }
    }
    ログイン後にコピー

    上記のコードからわかるように、スレッドの安全性と高いパフォーマンスを確保するために、コード内で if と synchronized が 2 回使用されています。プログラムの実行を確実にするため。では、スレッドの安全性を確保するためにすでに synchronized が行われているのに、なぜ変数に volatile を追加する必要があるのでしょうか?この問題を説明する前に、まず前提条件となる知識を理解する必要があります: volatile の用途は何ですか?

    1. Volatile 関数

    volatile には 2 つの主な機能があります。1 つ目はメモリの可視性の問題を解決し、2 つ目は命令の並べ替えを防止します。

    1.1 メモリ可視性の問題

    いわゆるメモリ可視性問題とは、複数のスレッドが同時に変数を操作する場合を指します。1 つのスレッドが変数の値を変更した後、他のスレッドがスレッド 変数の変更は認識できません。これはメモリの可視性の問題です。 volatile を使用すると、メモリ可視性の問題を解決できます。 次のコードのように、volatile が追加されていない場合、その実装は次のようになります。

    private static boolean flag = false;
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 如果 flag 变量为 true 就终止执行
                while (!flag) {
    
                }
                System.out.println("终止执行");
            }
        });
        t1.start();
        // 1s 之后将 flag 变量的值修改为 true
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("设置 flag 变量的值为 true!");
                flag = true;
            }
        });
        t2.start();
    }
    ログイン後にコピー

    実行結果上記のプログラムは次のようになります:

    Java シングルトン モードに volatile キーワードを追加する必要があるのはなぜですか?

    ただし、上記のプログラムを N 回実行してもまだ終了していません。これは、スレッド 2 が変更されたことを示しています。フラグ変数、スレッド 1 は変数の変更を認識しませんでした。

    次に、フラグに volatile を追加してみます。実装コードは次のとおりです。

    public class volatileTest {
        private static volatile boolean flag = false;
        public static void main(String[] args) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    // 如果 flag 变量为 true 就终止执行
                    while (!flag) {
    
                    }
                    System.out.println("终止执行");
                }
            });
            t1.start();
            // 1s 之后将 flag 变量的值修改为 true
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("设置 flag 变量的值为 true!");
                    flag = true;
                }
            });
            t2.start();
        }
    }
    ログイン後にコピー

    上記プログラムの実行結果は次のようになります。

    Java シングルトン モードに volatile キーワードを追加する必要があるのはなぜですか?

    上記の実行結果から、volatile を使用するとプログラム内のメモリ可視性の問題を解決できることがわかります。

    1.2 命令の並べ替えの防止

    命令の並べ替えとは、プログラムの実行中に、コンパイラまたは JVM がプログラムの実行パフォーマンスを向上させるために命令の順序を頻繁に並べ替えることを意味します。命令の並べ替えの本来の設計意図は確かに非常に優れており、シングル スレッドでも大きな役割を果たすことができますが、マルチスレッドでは命令の並べ替えを使用するとスレッドの安全性の問題が発生する可能性があります。

    いわゆるスレッド セーフティの問題とは、プログラムの実行結果が期待と一致しないことを指します。たとえば、予期した正しい結果が 0 であるにもかかわらず、プログラムの実行結果が 1 である場合、これはスレッド セーフティの問題です。

    volatile を使用すると命令の並べ替えを禁止できるため、複数のスレッドで実行するときにプログラムを正しく実行できます。

    2. なぜ volatile を使用するのでしょうか?

    話題に戻りますが、 シングルトン モードでは volatile を使用します。主な理由は、volatile は命令の並べ替えを禁止し、それによってプログラム の通常の動作を確保できるからです。ここで読者の中には、スレッドの安全性を確保するために synchronized がすでに使用されているのではないかという疑問を持つ人もいるかもしれません。では、なぜ volatile を追加するのでしょうか?次のコードを見てください:

    public class Singleton {
        private Singleton() {}
        // 使用 volatile 禁止指令重排序
        private static volatile Singleton instance = null;
        public static Singleton getInstance() {
            if (instance == null) { // ①
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton(); // ②
                    }
                }
            }
            return instance;
        }
    }
    ログイン後にコピー

    上記のコードに注目してください。コードの 2 行の①と②にマークを付けました。プライベート変数に volatile を追加するのは、主に②の実行時、つまり「instance = new Singleton()」の実行時に命令が並べ替えられるのを防ぐためです。実際の実行は次の 3 つのステップに分かれています。

    • メモリ空間を作成します。

    • #オブジェクト Singleton をメモリ空間で初期化します。

    • #メモリ アドレスをインスタンス オブジェクトに割り当てます (この手順を実行すると、インスタンスは null に等しくなくなります)。

    想像してみてください。

    volatile が追加されていない場合、スレッド 1 は上記のコードの②を実行するときに命令の並べ替えを実行し、元の実行順序を変更する可能性があります。 1、2、3 を 1、3、2 に並べ替えます。ただし、特殊な状況では、スレッド 1 がステップ 3 を実行した後、スレッド 2 が来て上記のコードの最初のステップを実行すると、インスタンス オブジェクトは null ではないが、スレッド 1 はまだオブジェクトのインスタンス化を完了していないと判断されます。スレッド 2 はインスタンス化された「半分」のオブジェクトを取得し、プログラム実行エラーが発生するため、プライベート変数に volatile が追加されます。

    以上がJava シングルトン モードに volatile キーワードを追加する必要があるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    AI Hentai Generator

    AI Hentai Generator

    AIヘンタイを無料で生成します。

    ホットツール

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

    Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

    ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

    Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

    Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

    Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

    Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

    この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

    Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

    Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

    Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

    Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

    カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

    カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

    Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Feb 07, 2025 pm 12:11 PM

    Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。

    See all articles