ホームページ Java &#&チュートリアル 揮発性キーワードの深い理解

揮発性キーワードの深い理解

Sep 07, 2019 pm 04:44 PM
java volatile

揮発性キーワードの深い理解

#volatile キーワードの深い理解

1.volatile と可視性

volatile が可視性を保証できることは誰もが知っていますが、それはどのようにして保証されるのでしょうか?

これは、Happen-before 原則に関連しています。この原則の 3 番目の規定は、volatile で変更された変数の場合、書き込み操作は変数の読み取り操作よりも前に行う必要があるということです。具体的な手順は次のとおりです。

A スレッドは共有変数を作業メモリに読み込み、同時に B スレッドも共有変数を作業メモリに読み込みます。

スレッド A が共有変数を変更すると、すぐにメイン メモリに更新されます。このとき、スレッド B の作業メモリ内の共有変数は無効に設定され、新しい値が必要になります。メインメモリから再読み取りされます。ハードウェアに反映され、CPU のキャッシュ ラインが無効な状態に設定されます。

これにより可視性が確保されます。簡単に言うと、スレッドが volatile-modified 変数を変更してメイン メモリに更新した後、他のスレッドの作業メモリにある共有変数が無効になるため、共有変数をスレッドから取得する必要があります。メインメモリ。もう一度読んでください。

2. 不安定性と秩序性

不安定性が秩序性を保証できることは誰もが知っていますが、それはどのようにして保証されるのでしょうか?

volatile は順序性を保証し、比較的簡単です。これにより、JVM とプロセッサが volatile キーワードで変更された変数の命令を並べ替えることができなくなりますが、変数の前後の変数は、最終結果に限り任意に並べ替えることができます。は変数の値と同じです。変更前の結果の一貫性を保つだけです。

基本的な原則

volatile によって変更された変数には、下部に「lock:」というプレフィックスが付けられます。「lock」プレフィックスの付いた命令は、次の命令と同等です。メモリ バリア。これはまさに可視性と秩序性を確保するための鍵です。このバリアの主な機能は次のとおりです:

命令が再配置されるとき、バリアの前のコードはバリアの後ろに再配置することはできません。バリアの後のコードをバリアの前に再配置します。

メモリ バリアを実行するときは、以前のコードがすべて実行されていること、および実行結果がバリア後のコードに表示されていることを確認してください。

作業メモリ内の変数を強制的にメインメモリにフラッシュします。

他のスレッドの作業メモリ内の変数は無効に設定されるため、メイン メモリから再度読み取る必要があります。

3. Volatile とアトミック性

volatile がアトミック性を保証できないことは誰もが知っていますが、なぜアトミック性を保証できないのでしょうか?

コードのデモ:

package com.github.excellent01;

import java.util.concurrent.CountDownLatch;

/**
 * @auther plg
 * @date 2019/5/19 9:37
 */
public class TestVolatile implements Runnable {
    private volatile Integer num = 0;
    private static CountDownLatch latch = new CountDownLatch(10);
    @Override
    public void run() {
        for(int i = 0; i < 1000; i++){
            num++;
        }
        latch.countDown();
    }

    public Integer getNum() {
        return num;
    }

    public static void main(String[] args) throws InterruptedException {
        TestVolatile test = new TestVolatile();
        for(int i = 0; i < 10; i++){
            new Thread(test).start();
        }
        latch.await();
        System.out.println(test.getNum());
    }
}
ログイン後にコピー

10 個のスレッドを開始し、各スレッドが共有変数 num を 1000 回追加し、すべてのスレッドが実行を完了したときに、num の最終結果を出力します。

揮発性キーワードの深い理解

10,000 になることはめったにありません。これは、volatile ではアトミック性が保証できないためです。

原因分析:

num の操作は 3 つのステップで構成されます:

num をメイン メモリから作業メモリに読み取ります。中

作業メモリに1つ追加します

追加が完了したら、メインメモリに書き戻します。

これら 3 つのステップはすべてアトミックな操作ですが、これらを合わせてもアトミックな操作ではないため、各ステップは実行中に中断される可能性があります。

このとき num の値が 10 であるとします。スレッド A は変数を自身のワーキング メモリに読み込みます。このとき CPU スイッチが発生します。B も num を自身のワーキング メモリに読み込みます。このとき、スレッド A は変数を自身のワーキング メモリに読み込みます。スレッド B は自身の作業メモリ内の num の値を変更して 11 に変更しますが、この時点ではメイン メモリにリフレッシュされていないため、スレッド A はその値を知りません。 num の値が変更されました。前に述べたように、volatile 変数が変更されると、他のスレッドはそれをすぐに認識します。前提条件として、最初にメイン メモリに更新する必要があります。このとき、他のスレッドは共有変数の値を設定します。彼らが取り組んでいる変数が無効になります。メインメモリにリフレッシュされていないため、A は愚かにも知らず、10 に 1 を加算しました。 したがって、最終的には両方のスレッドがインクリメント操作を実行しましたが、最終的な結果は 1 回だけ加算されました。

これが、volatile がアトミック性を保証できない理由です。

volatile の使用シナリオ

volatile の特性によると、順序性と可視性は保証されますが、原子性は保証されないため、volatile はそうでないものにも使用できます。 require atomicity. 、またはアトミック性が保証されている場合:

コードデモ

volatile boolean shutdownRequested 
public void shutdown() {
  shutdownRequested = true;
}
public void work() {
  while(shutdownRequested) {
    //do stuff
 }
}
ログイン後にコピー

スレッドが shutdownRequested を変更する限り、作業を実行しているスレッドはそれをすぐに認識するため、作業はすぐに停止します。そうでない場合 volatile が追加されると、作業メモリからデータを読み取るたびに常に true になり、他の人が停止したことを知らずに継続的に実行されます。

コードのデモ:

package com.github.excellent;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 启动线程会被阻塞,flag 从内存读入,会存入寄存器中,下次直接从寄存器取值
 * 因此值一直是false
 * 即使别的线程已经将值更改了,它也不知道
 * 加volatile即可。也可以加锁,只要保证内存可见性即可
 * @auther plg
 * @date 2019/5/2 22:40
 */
public class Testvolatile {
    public static  boolean flag = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(()->{
            for(;;) {
                System.out.println(flag);
            }
        });
        Thread thread2 = new Thread(()->{
            for(;;){
                flag = true;
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}
ログイン後にコピー

実行結果:

揮発性キーワードの深い理解

これはとても愚かです。他の人がそれを知らずに変更したにもかかわらず、依然として出力されます間違い。 volatile を追加するだけでOKです。

以上が揮発性キーワードの深い理解の詳細内容です。詳細については、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:26 PM

Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

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

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

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

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

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

Javaのアームストロング数 Javaのアームストロング数 Aug 30, 2024 pm 04:26 PM

Java のアームストロング番号に関するガイド。ここでは、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つの操作を実行する端末操作です。その設計意図はです

See all articles