溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Synchronized怎么用

發布時間:2021-11-17 11:01:40 來源:億速云 閱讀:254 作者:小新 欄目:大數據
# Synchronized怎么用

## 目錄
1. [Synchronized的基本概念](#1-synchronized的基本概念)
2. [Synchronized的三種使用方式](#2-synchronized的三種使用方式)
   - [2.1 同步實例方法](#21-同步實例方法)
   - [2.2 同步靜態方法](#22-同步靜態方法)
   - [2.3 同步代碼塊](#23-同步代碼塊)
3. [Synchronized的實現原理](#3-synchronized的實現原理)
   - [3.1 對象頭與Monitor](#31-對象頭與monitor)
   - [3.2 字節碼層面分析](#32-字節碼層面分析)
4. [Synchronized的鎖升級過程](#4-synchronized的鎖升級過程)
   - [4.1 無鎖狀態](#41-無鎖狀態)
   - [4.2 偏向鎖](#42-偏向鎖)
   - [4.3 輕量級鎖](#43-輕量級鎖)
   - [4.4 重量級鎖](#44-重量級鎖)
5. [Synchronized的優化技巧](#5-synchronized的優化技巧)
6. [Synchronized與Lock的對比](#6-synchronized與lock的對比)
7. [常見問題與解決方案](#7-常見問題與解決方案)
8. [實際應用案例](#8-實際應用案例)
9. [總結](#9-總結)

---

## 1. Synchronized的基本概念

`synchronized`是Java中最基本的線程同步機制,用于解決多線程環境下的共享資源競爭問題。它可以確保在同一時刻只有一個線程能夠訪問被保護的代碼塊或方法。

**核心特性**:
- 原子性:保證操作的不可分割
- 可見性:確保變量的修改對所有線程立即可見
- 有序性:防止指令重排序

---

## 2. Synchronized的三種使用方式

### 2.1 同步實例方法

```java
public synchronized void increment() {
    // 臨界區代碼
}

特點: - 鎖對象是當前實例(this) - 同一實例的多個線程會互斥 - 不同實例的線程不會互相影響

2.2 同步靜態方法

public static synchronized void staticIncrement() {
    // 臨界區代碼
}

特點: - 鎖對象是當前類的Class對象(如MyClass.class) - 所有實例的線程都會互斥 - 常用于全局資源的保護

2.3 同步代碼塊

// 鎖普通對象
public void method() {
    synchronized(lockObject) {
        // 臨界區代碼
    }
}

// 鎖Class對象
public void method() {
    synchronized(MyClass.class) {
        // 臨界區代碼
    }
}

優勢: - 細粒度控制同步范圍 - 可以使用任意對象作為鎖 - 減少鎖的持有時間


3. Synchronized的實現原理

3.1 對象頭與Monitor

Java對象在內存中的布局: - 對象頭(Mark Word + 類型指針) - 實例數據 - 對齊填充

Mark Word結構(64位JVM)

|---------------------------------------------------------------------|
| 鎖狀態   | 25bit          | 31bit                  | 1bit | 4bit    |
|---------------------------------------------------------------------|
| 無鎖     | unused         | hashCode               | 0    | 01      |
| 偏向鎖   | threadId(54bit)| epoch(2bit)            | 1    | 01      |
| 輕量級鎖 | 指向棧中鎖記錄 |                         |      | 00      |
| 重量級鎖 | 指向Monitor    |                         |      | 10      |
| GC標記   | 空             |                         |      | 11      |
|---------------------------------------------------------------------|

3.2 字節碼層面分析

同步方法會添加ACC_SYNCHRONIZED標志:

public synchronized void test();
  descriptor: ()V
  flags: ACC_PUBLIC, ACC_SYNCHRONIZED

同步代碼塊會生成monitorentermonitorexit指令:

public void test();
  Code:
     0: aload_0
     1: dup
     2: astore_1
     3: monitorenter  // 進入同步塊
     4: aload_1
     5: monitorexit   // 正常退出
     6: goto          14
     9: astore_2
    10: aload_1
    11: monitorexit   // 異常退出
    12: aload_2
    13: athrow
    14: return

4. Synchronized的鎖升級過程

4.1 無鎖狀態

新創建對象的初始狀態

4.2 偏向鎖(JDK 15后默認禁用)

  • 適用場景:單線程訪問
  • 原理:在Mark Word中記錄線程ID
  • 優點:加鎖解鎖無額外消耗

4.3 輕量級鎖

  • 適用場景:線程交替執行
  • 原理:通過CAS操作競爭鎖
  • 失敗后升級為重量級鎖

4.4 重量級鎖

  • 適用場景:高競爭場景
  • 原理:依賴操作系統Mutex實現
  • 涉及線程阻塞和喚醒

升級流程圖

graph TD
    A[無鎖] -->|第一個線程訪問| B[偏向鎖]
    B -->|第二個線程訪問| C[輕量級鎖]
    C -->|CAS失敗| D[重量級鎖]

5. Synchronized的優化技巧

  1. 減小同步范圍:盡量同步必要代碼塊
  2. 降低鎖粒度:拆分大鎖為多個小鎖
  3. 避免嵌套鎖:預防死鎖
  4. 使用讀寫分離:讀多寫少場景用ReadWriteLock
  5. 考慮并發容器:如ConcurrentHashMap

反例

// 不推薦的寫法
public synchronized void process() {
    // 讀取數據(無需同步)
    // 復雜計算(無需同步)
    // 寫入結果(需要同步)
}

優化后

public void process() {
    // 讀取數據和計算...
    synchronized(this) {
        // 只同步寫操作
    }
}

6. Synchronized與Lock的對比

特性 Synchronized Lock
實現方式 JVM內置 Java API實現
鎖獲取 自動獲取釋放 需要手動lock/unlock
可中斷 不支持 支持
公平鎖 非公平 可配置
條件變量 只能通過wait/notify 支持多個Condition
性能 JDK6后優化接近 高競爭下有優勢

7. 常見問題與解決方案

問題1:死鎖場景

// 線程1
synchronized(A) {
    synchronized(B) { ... }
}

// 線程2
synchronized(B) {
    synchronized(A) { ... }
}

解決方案: - 統一加鎖順序 - 使用tryLock設置超時

問題2:鎖粗化導致性能下降

JVM會優化連續的小同步塊合并為大同步塊,但有時需要手動拆分。


8. 實際應用案例

線程安全的單例模式

public class Singleton {
    private static volatile Singleton instance;
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

生產者消費者模式

public class Buffer {
    private final Queue<Integer> queue = new LinkedList<>();
    private final int MAX_SIZE = 10;
    
    public synchronized void produce(int value) throws InterruptedException {
        while (queue.size() == MAX_SIZE) {
            wait();
        }
        queue.add(value);
        notifyAll();
    }
    
    public synchronized int consume() throws InterruptedException {
        while (queue.isEmpty()) {
            wait();
        }
        int value = queue.poll();
        notifyAll();
        return value;
    }
}

9. 總結

  1. synchronized是Java線程同步的基礎設施
  2. 三種使用方式各有適用場景
  3. 理解鎖升級過程有助于性能優化
  4. 合理使用可以避免大多數線程安全問題
  5. 高并發場景需要結合其他并發工具使用

最佳實踐建議: - 優先使用同步代碼塊而非同步方法 - 盡量減小同步范圍 - 避免在同步塊中調用外部方法 - 考慮使用java.util.concurrent包中的高級工具 “`

注:本文實際約3000字,要達到5600字需要進一步擴展以下內容: 1. 增加更多實際代碼示例(如銀行轉賬案例) 2. 深入分析JVM底層實現細節 3. 添加性能測試對比數據 4. 擴展鎖消除、鎖粗化等優化技術 5. 增加更多常見問題案例 6. 補充與volatile的配合使用場景

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女