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

Java 多線程中 Boolean 常量同步陷阱:自動裝箱導致鎖失效與常量池共享誤阻塞

     編輯:Java 相關知識

現象一:自動裝箱導致鎖對象變更

private volatile Boolean flag = false;
public void method() {
    synchronized (flag) { // 看似同一把鎖
        flag = !flag;     // 自動裝箱:flag 指向 Boolean.TRUE 或 Boolean.FALSE
        // 此時其他線程可能持有舊 Boolean 對象的鎖,導致同步失效
    }
}

原因:false → Boolean.FALSE,true → Boolean.TRUE。修改變量值實際是變量指向不同的常量對象,synchronized 鎖住的是對象頭,對象變了鎖就失效。

現象二:常量池共享導致無關鎖互斥

private volatile Boolean lock1 = Boolean.FALSE;
private volatile Boolean lock2 = false; // 也是 Boolean.FALSE
public void methodA() { synchronized(lock1) { ... } }
public void methodB() { synchronized(lock2) { ... } }

原因:Boolean.FALSE 和 false 都指向常量池中同一個 Boolean.FALSE 實例。本應獨立的兩把鎖變成同一把,導致 methodA 和 methodB 錯誤串行化。

驗證代碼

public class BooleanSyncTest {
    private volatile Boolean flag = Boolean.FALSE;
    public void test() {
        for (int i=0; i<10; i++) {
            new Thread(() -> {
                synchronized (flag) {
                    flag = !flag;
                    System.out.println(Thread.currentThread().getName() + " flag=" + flag);
                    try { Thread.sleep((long)(Math.random()*1000)); } catch (Exception e) {}
                    if (!flag) System.out.println(Thread.currentThread().getName() + " 同步失效!");
                    flag = !flag;
                }
            }).start();
        }
    }
    public static void main(String[] args) {
        new BooleanSyncTest().test();
    }
}
// 運行會間歇性輸出「同步失效!」

正確做法

  1. 專用鎖對象:private final Object lock = new Object();
  2. new Boolean():private final Boolean lock = new Boolean(false);(每次 new 創建新對象)
  3. 避免鎖住基本類型包裝類常量:Integer、Long、String 同理

最佳實踐總結

  • 永遠使用 private final Object lock = new Object(); 作為同步鎖
  • 業務標誌位用 volatile boolean(基本類型),同步用獨立鎖對象
  • 代碼審查時重點檢查 synchronized(包裝類變量) 模式
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved