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

Java synchronized 區塊同步變數:字串重新賦值導致鎖失效的陷阱與解決

     編輯:Java 相關知識

現象:同步區塊卻輸出兩行


private static String lock = "";
synchronized(lock) {
    lock = "changed"; // 關鍵錯誤!
    while (true);     // 無限迴圈
}

兩執行緒分別呼叫兩個同步方法,理應只有一個進入無限迴圈,但實際輸出:


method1
staticMethod1

說明兩執行緒同時進入了同步區塊,同步失效。

根因:String 不可變,重新賦值換新物件


String s = "hello";
System.out.println(s.hashCode()); // 123
s = "world";
System.out.println(s.hashCode()); // 456  // hashCode 改變 = 新物件
  • 執行緒 A 進入 synchronized(lock),鎖住「舊字串物件」。
  • 執行緒 A 執行 lock = "changed",lock 參考指向「新字串物件」。
  • 執行緒 B 進入 synchronized(lock),鎖住的是「新字串物件」,與 A 鎖不同,不互斥。

解決方案:final 宣告鎖物件


private final static String LOCK = ""; // 編譯期保證不被重新賦值
// 或
private final static Object LOCK = new Object(); // 推薦:專用不可變物件
  • final 保證參考不變,鎖物件恆為同一個。
  • 慣例使用 new Object() 或 new byte[0] 作為純鎖物件,語意清晰。

兩種理解角度

  1. 方法視角:用類變數鎖住關鍵方法,確保同一時間只有一個執行緒執行。
  2. 變數視角:用同步區塊保護共享變數,確保同一時間只有一個執行緒讀寫。

本質相同:監視器鎖的互斥性。

注意事項

  • synchronized 參數必須是物件參考,基本型別(int、boolean 等)無法直接同步。
  • 同步區塊內嚴禁修改鎖參考,若需動態鎖,請用 ConcurrentHashMap 等進階結構。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved