首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java多線程同步:共享可變數據的正確訪問與volatile關鍵字應用

     編輯:Java 相關知識

前言

在多線程程式設計中,若對共享的可變數據訪問缺乏同步機制,後果往往十分嚴重,即使該變量具備原子讀寫特性也不例外。本文將透過具體代碼示例,深入剖析線程同步的核心問題,並展示如何使用 synchronized 與 volatile 關鍵字正確解決數據可見性問題。

問題演示:缺乏同步的後果

考慮以下程式片段,主線程啟動一個後台線程執行計數任務,約 1 秒後嘗試通過設置 stopRequested 標誌來停止該線程:

import java.util.concurrent.TimeUnit;

public class StopThread {
    private static boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(() -> {
            int i = 0;
            while (!stopRequested) {
                i++;
                System.out.println(i);
            }
        });
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

直覺上程式應在 1 秒後結束,但實際執行時後台線程會無限循環。原因在於:後台線程無法看到主線程對 stopRequested 的修改,這就是未同步導致的「數據不可見」問題。

方案一:使用 synchronized 實現同步

為確保讀寫操作的原子性與可見性,必須對讀寫方法均加鎖:

public class StopThread {
    private static boolean stopRequested;

    private static synchronized void requestStop() {
        stopRequested = true;
    }

    private static synchronized boolean stopRequested() {
        return stopRequested;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(() -> {
            int i = 0;
            while (!stopRequested()) {
                i++;
                System.out.println(i);
            }
        });
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        requestStop();
    }
}

關鍵點: 寫方法(requestStop)與讀方法(stopRequested)皆需聲明 synchronized,否則無法構成真正的同步語義。

方案二:使用 volatile 簡化同步

volatile 關鍵字能保證變量對所有線程的可見性,且禁止指令重排,是解決此類問題的輕量級方案:

public class StopThread {
    private static volatile boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(() -> {
            int i = 0;
            while (!stopRequested) {
                i++;
                System.out.println(i);
            }
        });
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

此寫法碼簡潔、語義清晰,適用於單一變量的狀態標誌場景。

總結

  • 共享可變數據必須同步,否則會發生數據不可見等嚴重問題。
  • synchronized 需對讀寫雙方同步,開銷較大但功能完整。
  • volatile 適合單變量狀態標誌,無鎖開銷,效能更優。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved