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

Java 多線程同步代碼塊:解決線程安全問題的核心機制

     編輯:Java 綜合教學

Java 多線程同步代碼塊:解決線程安全問題的核心機制

為什麼會出現線程安全問題?

多線程並發訪問共享數據時,若操作非原子性(多條語句組合),可能發生:

  1. 線程 A 判斷條件滿足,準備執行
  2. 線程 B 同樣判斷條件滿足,搶佔 CPU 執行並修改共享數據
  3. 線程 A 繼續執行,基於過期數據操作 → 數據不一致

典型案例:售票系統 4 個線程賣 100 張票,出現 0、-1、-2 錯票。

同步代碼塊語法與原理

synchronized (鎖對象) {
    // 操作共享數據的代碼(臨界區)
}

關鍵規則

  • 鎖對象任意,但多線程必須共用同一把鎖
  • 持有鎖的線程進入同步塊,其他線程阻塞等待
  • 同步塊執行完畢自動釋放鎖(異常也會釋放)
  • 前提:≥2 個線程 + 同一把鎖 + 操作共享數據

實戰:同步修正售票系統

class Ticket implements Runnable {
    private static int tickets = 100;
    private final Object lock = new Object(); // 共享鎖
    
    public void run() {
        while (true) {
            synchronized (lock) { // 同步塊包裹判斷+操作
                if (tickets > 0) {
                    try { Thread.sleep(10); } catch (InterruptedException e) {}
                    System.out.println(Thread.currentThread().getName() 
                        + " sale: " + tickets--);
                } else {
                    break; // 賣完退出
                }
            }
        }
    }
}

public class TicketDemo {
    public static void main(String[] args) {
        Ticket task = new Ticket(); // 同一任務實例 → 共享 tickets + lock
        new Thread(task, "窗口A").start();
        new Thread(task, "窗口B").start();
        new Thread(task, "窗口C").start();
        new Thread(task, "窗口D").start();
    }
}

關鍵點解析

  1. Runnable 實例共享 tickets 與 lock
  2. synchronized(lock) 確保「判斷 > 睡眠 > 輸出 > 遞減」原子執行
  3. 若將 synchronized 加在 run() 方法上 → 效率極低(全程串行)
  4. 鎖對象也可用 this、Ticket.class,但需確保同一實例/類

同步的優缺點與進階

優點缺點
解決線程安全,數據一致性上下文切換、鎖競爭消耗 CPU
實現簡單,JVM 原生支援易導致死鎖(多鎖嵌套)

進階替代方案

  • Lock 介面:ReentrantLock 支援可中斷、超時、公平鎖、條件變量
  • 原子類:AtomicInteger 等 CAS 無鎖操作,適合計數器場景
  • 並發集合:ConcurrentHashMap、CopyOnWriteArrayList
  • ThreadLocal:線程隔離,避免共享

總結

同步代碼塊是 Java 解決併發安全的基石,核心在於縮小同步範圍、選擇正確鎖對象、確保共享鎖。實戰中優先考慮無鎖數據結構、不可變對象、線程封閉,必要時再使用同步或 Lock。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved