Java中volatile關(guān)鍵字的作用是什么舉例詳解
前言
volatile 是 Java 中的一個關(guān)鍵字,用于修飾變量。它提供了 可見性 和 禁止指令重排 的特性,但不保證 原子性。
1. 可見性 (Visibility)
- 問題背景: 在多線程環(huán)境下,每個線程都有自己的工作內(nèi)存(例如 CPU 緩存),線程對共享變量的讀寫操作可能不是直接在主內(nèi)存中進(jìn)行的,而是在工作內(nèi)存中進(jìn)行的。這可能導(dǎo)致一個線程修改了共享變量的值,而其他線程卻看不到這個修改,從而讀取到過期的值。
- volatile 的作用: 當(dāng)一個變量被
volatile修飾時,它會保證:- 寫操作: 當(dāng)一個線程修改了
volatile變量的值,這個新值會立即被 刷新 到主內(nèi)存中。 - 讀操作: 當(dāng)一個線程讀取
volatile變量時,它會從主內(nèi)存中讀取最新的值,而不是從自己的工作內(nèi)存中讀取。
- 寫操作: 當(dāng)一個線程修改了
- 實現(xiàn)原理:
volatile通過 內(nèi)存屏障 (Memory Barrier) 來實現(xiàn)可見性。內(nèi)存屏障是一種 CPU 指令,它可以阻止編譯器和 CPU 對指令進(jìn)行重排序,并強(qiáng)制將工作內(nèi)存中的數(shù)據(jù)刷新到主內(nèi)存,或從主內(nèi)存讀取數(shù)據(jù)。
代碼示例:
public class VolatileVisibilityExample {
private static volatile boolean flag = false;
// private static boolean flag = false; 如果不使用volatile,可能出現(xiàn)線程1無法停止的情況
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
while (!flag) {
// ... (循環(huán)執(zhí)行某些操作) ...
}
System.out.println("Thread 1 stopped.");
});
Thread thread2 = new Thread(() -> {
try {
Thread.sleep(1000); // 讓 thread1 先執(zhí)行
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true; // 修改 flag 的值
System.out.println("Thread 2 set flag to true.");
});
thread1.start();
thread2.start();
}
}
2. 禁止指令重排 (Ordering)
- 問題背景: 為了優(yōu)化性能,編譯器和 CPU 可能會對指令的執(zhí)行順序進(jìn)行重排序(reordering),只要不影響單線程程序的執(zhí)行結(jié)果。但在多線程環(huán)境下,指令重排可能導(dǎo)致程序出現(xiàn)意外的行為。
- volatile 的作用:
volatile關(guān)鍵字可以禁止特定類型的指令重排:- 寫后讀: 不能將
volatile變量的寫操作重排到讀操作之后。 - 寫后寫: 不能將
volatile變量的寫操作重排到另一個volatile變量的寫操作之后。 - 讀后讀/寫: 不能將
volatile變量的讀操作重排到另一個volatile變量的讀操作或?qū)懖僮髦蟆?/li>
- 寫后讀: 不能將
- 實現(xiàn)原理:
volatile通過插入特定類型的內(nèi)存屏障來禁止指令重排。例如,在volatile變量的寫操作之后會插入一個 StoreStore 屏障,在讀操作之前會插入一個 LoadLoad 屏障,以及可能的StoreLoad屏障。 - 雙重檢查鎖定 (Double-Checked Locking) 的例子:
volatile經(jīng)常用于雙重檢查鎖定模式,以防止指令重排導(dǎo)致的問題。//單例模式 public class Singleton{ //使用volatile禁止instance = new Singleton()的指令重排 private static volatile Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ //第一次檢查 synchronized(Singleton.class){ if(instance == null){ //第二次檢查,防止多個線程同時通過第一次檢查 instance = new Singleton(); } } } return instance; } }
3. 不保證原子性 (Atomicity)
- 重要說明:
volatile不保證 操作的原子性。原子性指的是一個操作是不可分割的,要么全部執(zhí)行,要么不執(zhí)行,不會出現(xiàn)執(zhí)行一半的情況。 - 例子:
volatile變量的自增操作 (i++) 不是原子性的。它實際上包含了三個步驟:讀取i的值、將i的值加 1、將新值寫回i。在多線程環(huán)境下,這三個步驟之間可能會被其他線程打斷,導(dǎo)致結(jié)果錯誤。 - **解決:**如果需要保證原子性,可以使用
synchronized、ReentrantLock或原子類(如AtomicInteger)。
總結(jié):
volatile關(guān)鍵字用于修飾變量,提供可見性和禁止指令重排的特性。- 可見性保證線程對
volatile變量的讀寫操作都是直接在主內(nèi)存中進(jìn)行的。 - 禁止指令重排防止編譯器和 CPU 對
volatile變量相關(guān)的指令進(jìn)行重排序。 volatile不保證 原子性。volatile通常用于狀態(tài)標(biāo)志、雙重檢查鎖定等場景。
問題分析:
這個問題考察了對 volatile 關(guān)鍵字的理解,包括它的作用、特性(可見性、禁止指令重排)以及局限性(不保證原子性)。回答時需要清晰地解釋這些概念,并提供一些代碼示例來說明問題。
與其他問題的知識點聯(lián)系:
- 什么是 Java 內(nèi)存模型(JMM)?
volatile是 Java 內(nèi)存模型 (JMM) 的一部分,它定義了線程和主內(nèi)存之間的交互規(guī)則。 - 什么是 Java 中的原子性、可見性和有序性?
volatile提供了可見性和有序性(禁止指令重排),但不保證原子性。 - 什么是 Java 的 happens-before 規(guī)則?
volatile變量的寫操作 happens-before 于后續(xù)對該變量的讀操作。 - 什么是 Java 中的指令重排?
volatile可以禁止特定類型的指令重排。 - Java 中的 synchronized 是怎么實現(xiàn)的?
synchronized提供了原子性、可見性和有序性。在某些情況下,volatile可以作為synchronized的一種輕量級替代方案(如果只需要保證可見性和有序性)。 - 你使用過 Java 中的哪些原子類? 原子類(如
AtomicInteger)提供了原子操作,可以用來替代volatile+ 額外同步的方案。 - Java 中的 final 關(guān)鍵字是否能保證變量的可見性? final關(guān)鍵字可以保證可見性。
理解這些聯(lián)系可以幫助你更全面地掌握 Java 并發(fā)編程的知識,并了解如何在實際應(yīng)用中選擇合適的同步機(jī)制。
到此這篇關(guān)于Java中volatile關(guān)鍵字的作用是什么的文章就介紹到這了,更多相關(guān)Java volatile關(guān)鍵字的作用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 深入解析Java中volatile關(guān)鍵字的作用
- Java中volatile關(guān)鍵字的作用與用法詳解
- Java中Volatile關(guān)鍵字詳解及代碼示例
- Java中volatile關(guān)鍵字實現(xiàn)原理
- java多線程編程之慎重使用volatile關(guān)鍵字
- java volatile關(guān)鍵字使用方法及注意事項
- 談?wù)凧ava中Volatile關(guān)鍵字的理解
- 詳解Java面試官最愛問的volatile關(guān)鍵字
- 詳解Java線程編程中的volatile關(guān)鍵字的作用
- Java里volatile關(guān)鍵字是什么意思
相關(guān)文章
java中利用反射調(diào)用另一類的private方法的簡單實例
下面小編就為大家?guī)硪黄猨ava中利用反射調(diào)用另一類的private方法的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06
出現(xiàn)java.lang.NoSuchMethodException異常的解決(靠譜)
這篇文章主要介紹了出現(xiàn)java.lang.NoSuchMethodException異常的解決方案(靠譜),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
java 域?qū)ο蠊蚕頂?shù)據(jù)的實現(xiàn)
本文主要介紹了java 域?qū)ο蠊蚕頂?shù)據(jù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
Spring Boot2解決idea console 控制臺輸出亂碼的問題
這篇文章主要介紹了Spring Boot2解決idea console 控制臺輸出亂碼的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
java中hashCode方法與equals方法的用法總結(jié)
總的來說,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。前者集合內(nèi)的元素是有序的,元素可以重復(fù);后者元素?zé)o序,但元素不可重復(fù)2013-10-10
關(guān)于spring循環(huán)依賴問題及解決方案
這篇文章主要介紹了關(guān)于spring循環(huán)依賴問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06

