Java 中的 volatile

文章最後更新於 2024 年 6 月 11 日

簡介

volatile 是 Java 中的一個關鍵字,用於修飾變數。它的主要作用是確保變數在多執行緒環境中的可見性和有序性。

主要特性

  1. 可見性:當一個變數被聲明為 volatile 時,對該變數的讀寫操作將直接反映在主記憶體中。這意味著一個執行緒對 volatile 變數的修改對其他執行緒立即可見。
  2. 有序性volatile 關鍵字還能防止指令重排序。這意味著在讀寫 volatile 變數時,不會將該操作與之前或之後的操作重新排序。

使用範例

以下是使用 volatile 關鍵字的範例:

public class VolatileExample {
    private volatile boolean flag = false;

    public void writer() {
        flag = true; // 寫操作
    }

    public void reader() {
        if (flag) {
            // 讀操作,能夠立即看到 flag 的變化
            System.out.println("Flag has been set to true");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileExample example = new VolatileExample();

        Thread writerThread = new Thread(example::writer);
        Thread readerThread = new Thread(example::reader);

        writerThread.start();
        writerThread.join(); // 確保 writerThread 完成

        readerThread.start();
        readerThread.join(); // 確保 readerThread 完成
    }
}

在這個範例中,flag 被聲明為 volatile。當 writerThread 設置 flagtrue 時,readerThread 能夠立即看到這個變化並輸出 "Flag has been set to true"。

volatile vs synchronized

特性volatilesynchronized
可見性
有序性
原子性是(對整個臨界區域)
性能高(適用於簡單的狀態標誌)低(可能導致阻塞)
使用場景簡單的狀態標誌,避免指令重排序複雜的邏輯和需要原子性操作的代碼區塊

適用場景

  • 狀態標誌:適用於簡單的 boolean 標誌,用於多執行緒之間的通信。
  • 單例模式(Double-Checked Locking):在雙重檢查鎖的實現中,用於標誌實例是否已經初始化。

不適用場景

  • 複雜的邏輯操作:如果變數需要複雜的邏輯操作(如增減),則應該使用 synchronized 來確保原子性。
  • 非原子性操作volatile 無法確保操作的原子性,例如 i++

注意事項

  • volatile 不適用於解決所有的並發問題。對於需要原子性操作的場景,應該使用更高級的同步機制(如 synchronizedLock)。

關於作者

卡哥
卡哥
大家好,我是 Oscar(卡哥)。曾任 Yahoo 資深工程師(Lead Engineer),也是高智商組織 Mensa 的會員,擁有超過 15 年的軟體開發經驗。職涯中曾參與 Yahoo 關鍵字廣告、電子商務與搜尋相關專案,近年則在虛擬貨幣交易所專注於大數據與 AI 資料服務,帶領團隊開發具影響力的產品與解決方案。

在工作之外,我熱愛音樂,平時喜歡彈吉他、創作與演奏;運動方面偏好羽球、高爾夫球,也投入在美股與虛擬貨幣的投資領域。最享受的,是透過交流與分享,把知識與經驗轉化成更多可能性。