最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的synchronized關(guān)鍵字實現(xiàn)原理及使用方式

 更新時間:2025年09月24日 09:26:04   作者:夢兮760  
synchronized是Java中的關(guān)鍵字,用于實現(xiàn)線程同步,確保多個線程在訪問共享資源時的互斥性,本文將詳細解析synchronized的實現(xiàn)原理、使用方式以及優(yōu)化策略,感興趣的朋友一起看看吧

在多線程編程中,保證線程安全是至關(guān)重要的。Java提供了synchronized關(guān)鍵字作為一種簡單而有效的同步機制,用于控制多個線程對共享資源的訪問。本文將詳細解析synchronized的實現(xiàn)原理、使用方式以及優(yōu)化策略。

1. synchronized的基本概念

1.1 什么是synchronized

synchronized是Java中的關(guān)鍵字,用于實現(xiàn)線程同步,確保多個線程在訪問共享資源時的互斥性。它可以保證在同一時刻,只有一個線程可以執(zhí)行某個方法或代碼塊,從而避免數(shù)據(jù)不一致的問題。

1.2 為什么需要synchronized

在多線程環(huán)境下,如果多個線程同時訪問和修改共享數(shù)據(jù),可能會導(dǎo)致數(shù)據(jù)不一致的問題。例如:

public class Counter {
    private int count = 0;
    public void increment() {
        count++; // 非原子操作
    }
    public int getCount() {
        return count;
    }
}

count++看似是一個操作,但實際上包含三個步驟:

  1. 讀取count的當前值
  2. 將值加1
  3. 將新值寫回count

如果沒有同步機制,多個線程可能同時執(zhí)行這些步驟,導(dǎo)致結(jié)果不符合預(yù)期。

2. synchronized的三種使用方式

2.1 同步實例方法

public synchronized void increment() {
    count++;
}

synchronized修飾實例方法時,鎖對象是當前實例(this)。同一時刻,同一個實例的同步實例方法只能被一個線程訪問。

2.2 同步靜態(tài)方法

public static synchronized void staticIncrement() {
    staticCount++;
}

synchronized修飾靜態(tài)方法時,鎖對象是當前類的Class對象。同一時刻,該類的所有同步靜態(tài)方法只能被一個線程訪問。

2.3 同步代碼塊

public void increment() {
    synchronized(this) {
        count++;
    }
}
// 或者使用其他對象作為鎖
private final Object lock = new Object();
public void incrementWithLock() {
    synchronized(lock) {
        count++;
    }
}

同步代碼塊可以更精細地控制同步范圍,減少鎖的粒度,提高性能。

3. synchronized的實現(xiàn)原理

3.1 對象頭與Monitor

在JVM中,每個對象都包含一個對象頭,其中存儲了與鎖相關(guān)的信息。對象頭主要包括:

  • Mark Word:存儲對象的哈希碼、分代年齡、鎖標志位等
  • Klass Pointer:指向?qū)ο笏鶎兕惖脑獢?shù)據(jù)

當使用synchronized時,JVM會根據(jù)鎖標志位來判斷鎖的狀態(tài)。

3.2 Monitor機制

synchronized的實現(xiàn)依賴于Monitor(監(jiān)視器)機制。每個Java對象都與一個Monitor相關(guān)聯(lián),Monitor是線程同步的基本工具。

Monitor的基本結(jié)構(gòu)包含:

  • Owner:持有該Monitor的線程
  • EntryList:處于阻塞狀態(tài)的線程隊列
  • WaitSet:處于等待狀態(tài)的線程隊列

3.3 鎖的升級過程

為了平衡性能與安全性,Java中的鎖有幾種狀態(tài),并且可以根據(jù)競爭情況升級:

無鎖狀態(tài)

對象剛創(chuàng)建時,處于無鎖狀態(tài)。

偏向鎖

當?shù)谝粋€線程訪問同步塊時,會升級為偏向鎖。此時會在對象頭和棧幀中記錄偏向的線程ID。以后該線程進入同步塊時,不需要進行CAS操作來加鎖和解鎖,只需簡單測試一下對象頭的Mark Word是否指向當前線程。

輕量級鎖

當有第二個線程嘗試獲取鎖時,偏向鎖會升級為輕量級鎖。線程會通過CAS操作在棧幀中創(chuàng)建鎖記錄(Lock Record),并將對象頭的Mark Word復(fù)制到鎖記錄中,然后嘗試用CAS將對象頭的Mark Word替換為指向鎖記錄的指針。

重量級鎖

當輕量級鎖競爭激烈時(多個線程同時競爭),會升級為重量級鎖。此時未獲取到鎖的線程會進入阻塞狀態(tài),需要操作系統(tǒng)的介入來進行線程調(diào)度。

4. synchronized的底層實現(xiàn)

4.1 字節(jié)碼層面

從字節(jié)碼角度來看,synchronized同步代碼塊是通過monitorentermonitorexit指令實現(xiàn)的:

public void method() {
    synchronized(obj) {
        // 同步代碼塊
    }
}

對應(yīng)的字節(jié)碼:

0: aload_1           // 將obj引用壓入棧頂
1: dup               // 復(fù)制棧頂值
2: astore_2          // 將復(fù)制的引用存儲到局部變量表
3: monitorenter      // 進入監(jiān)視器
4: aload_2           // 將obj引用壓入棧頂
5: monitorexit       // 退出監(jiān)視器(正常退出)
6: goto 14
9: astore_3          // 異常處理開始
10: aload_2          // 將obj引用壓入棧頂
11: monitorexit      // 退出監(jiān)視器(異常退出)
12: aload_3
13: athrow
14: return           // 方法返回

4.2 內(nèi)存語義

synchronized具有以下內(nèi)存語義:

  1. 進入同步塊:將工作內(nèi)存中的共享變量清空,從主內(nèi)存重新加載
  2. 退出同步塊:將工作內(nèi)存中的修改刷新到主內(nèi)存

這保證了可見性和有序性,遵循h(huán)appens-before原則。

5. synchronized的特性

5.1 原子性

synchronized保證了被它修飾的代碼塊或方法是原子操作的。一次只有一個線程可以執(zhí)行同步代碼,不會被打斷。

5.2 可見性

當線程釋放鎖時,JMM會將工作內(nèi)存中的共享變量刷新到主內(nèi)存中。當線程獲取鎖時,JMM會使該線程的工作內(nèi)存無效,從主內(nèi)存重新加載共享變量。

5.3 有序性

synchronized通過"一個變量在同一時刻只允許一條線程對其進行l(wèi)ock操作"來保證有序性。同時,由于as-if-serial語義,同步代碼塊內(nèi)的指令可以重排序,但不會影響執(zhí)行結(jié)果。

5.4 可重入性

synchronized是可重入鎖,同一個線程可以多次獲取同一把鎖:

public class ReentrantExample {
    public synchronized void method1() {
        method2(); // 可以再次獲取鎖
    }
    public synchronized void method2() {
        // 方法實現(xiàn)
    }
}

6. synchronized的優(yōu)化策略

6.1 自旋鎖與自適應(yīng)自旋

為了避免線程在獲取鎖失敗時直接進入阻塞狀態(tài)(涉及操作系統(tǒng)內(nèi)核態(tài)切換,開銷大),JVM引入了自旋鎖。

自旋鎖的原理是:當線程獲取鎖失敗時,不立即阻塞,而是執(zhí)行一個空循環(huán)(自旋),在一定次數(shù)內(nèi)嘗試重新獲取鎖。如果自旋期間鎖被釋放,則可以避免線程阻塞。

自適應(yīng)自旋是自旋鎖的優(yōu)化,自旋時間不再固定,而是根據(jù)前一次在同一個鎖上的自旋時間以及鎖的擁有者的狀態(tài)來決定。

6.2 鎖消除

JVM在JIT編譯時,通過逃逸分析技術(shù),判斷同步塊使用的鎖對象是否只被一個線程訪問。如果是,則會消除這個同步操作。

public String concatString(String s1, String s2, String s3) {
    return s1 + s2 + s3;
}

在JDK 5之后,字符串連接會自動轉(zhuǎn)換為StringBuilder操作,而StringBuilder的append方法是同步的。但由于局部變量StringBuilder不會逃逸出方法,JVM會消除這些同步操作。

6.3 鎖粗化

如果一系列的連續(xù)操作都對同一個對象反復(fù)加鎖和解鎖,JVM會將鎖的同步范圍擴展(粗化)到整個操作序列的外部,減少不必要的鎖獲取和釋放。

public void method() {
    for(int i = 0; i < 100; i++) {
        synchronized(this) {
            // 操作
        }
    }
}

JVM可能會將鎖粗化為:

public void method() {
    synchronized(this) {
        for(int i = 0; i < 100; i++) {
            // 操作
        }
    }
}

7. synchronized的注意事項

7.1 性能考慮

雖然現(xiàn)代JVM對synchronized做了大量優(yōu)化,但在高并發(fā)場景下,它仍然可能成為性能瓶頸。需要考慮:

  1. 減少同步代碼塊的執(zhí)行時間
  2. 降低鎖的粒度(使用更細粒度的鎖)
  3. 考慮使用并發(fā)容器或其他并發(fā)工具

7.2 死鎖問題

synchronized可能導(dǎo)致死鎖,即兩個或多個線程互相等待對方釋放鎖:

// 線程1
synchronized(objA) {
    synchronized(objB) {
        // 操作
    }
}
// 線程2
synchronized(objB) {
    synchronized(objA) {
        // 操作
    }
}

避免死鎖的策略:

  1. 按固定順序獲取鎖
  2. 使用定時鎖(tryLock)
  3. 避免嵌套鎖

7.3 與Lock的比較

java.util.concurrent.locks.Lock相比,synchronized有以下特點:

特性synchronizedLock
實現(xiàn)機制JVM層面實現(xiàn)Java代碼實現(xiàn)
鎖的獲取自動獲取和釋放手動控制
可中斷性不支持支持
公平性非公平可選擇公平或非公平
條件變量通過wait/notify支持多個Condition

8. 實際應(yīng)用示例

8.1 線程安全的單例模式

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

8.2 生產(chǎn)者-消費者模式

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

9. 總結(jié)

synchronized是Java中實現(xiàn)線程同步的基本工具,它提供了簡單而有效的互斥機制。隨著JVM的發(fā)展,synchronized的性能已經(jīng)得到了顯著提升,在許多場景下可以滿足性能要求。

然而,在高并發(fā)場景下,開發(fā)人員仍需謹慎使用synchronized,考慮鎖的粒度、競爭情況以及可能的替代方案。理解synchronized的實現(xiàn)原理和優(yōu)化策略,有助于編寫出更高效、更安全的并發(fā)程序。

在實際開發(fā)中,應(yīng)根據(jù)具體需求選擇合適的同步機制,平衡性能、復(fù)雜性和可維護性。

到此這篇關(guān)于Java中的synchronized關(guān)鍵字實現(xiàn)原理及使用方式的文章就介紹到這了,更多相關(guān)java synchronized關(guān)鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中的HashMap實現(xiàn)原理深入理解

    Java中的HashMap實現(xiàn)原理深入理解

    HashMap是一種非常常見和實用的數(shù)據(jù)結(jié)構(gòu),它被廣泛應(yīng)用于Java編程中,這篇文章主要介紹了Java中HashMap實現(xiàn)原理的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-12-12
  • java的Jackson將json字符串轉(zhuǎn)換成泛型List

    java的Jackson將json字符串轉(zhuǎn)換成泛型List

    這篇文章主要介紹了java的Jackson將json字符串轉(zhuǎn)換成泛型List ,這里整理了詳細的代碼,有需要的小伙伴可以參考下。
    2017-02-02
  • springboot2.7報錯:request header is too large問題及解決

    springboot2.7報錯:request header is too la

    本文詳細介紹了在Spring Boot 2.7中使用@RequestParam傳參時,請求頭大小超過限制導(dǎo)致報錯的解決方案,包括調(diào)整配置文件、通過代碼配置和直接配置Tomcat等方法,并提醒注意事項
    2026-01-01
  • springboot?vue測試平臺接口定義前后端新增功能實現(xiàn)

    springboot?vue測試平臺接口定義前后端新增功能實現(xiàn)

    這篇文章主要介紹了springboot?vue測試平臺接口定義前后端新增功能實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • Java利用線程工廠監(jiān)控線程池的實現(xiàn)示例

    Java利用線程工廠監(jiān)控線程池的實現(xiàn)示例

    這篇文章主要介紹了Java利用線程工廠監(jiān)控線程池的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 通過簡單方法實現(xiàn)spring boot web項目

    通過簡單方法實現(xiàn)spring boot web項目

    這篇文章主要介紹了通過簡單方法實現(xiàn)spring boot web項目,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • IntelliJ IDEA 小技巧之Bookmark(書簽)的使用

    IntelliJ IDEA 小技巧之Bookmark(書簽)的使用

    這篇文章主要介紹了IntelliJ IDEA 小技巧之Bookmark(書簽)的使用,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • Java接口的簡單定義與實現(xiàn)方法示例

    Java接口的簡單定義與實現(xiàn)方法示例

    這篇文章主要介紹了Java接口的簡單定義與實現(xiàn)方法,結(jié)合實例形式分析了java面向?qū)ο蟪绦蛟O(shè)計中接口的概念、功能、定義及使用技巧,需要的朋友可以參考下
    2019-01-01
  • Spring MVC請求參數(shù)與響應(yīng)結(jié)果全局加密和解密詳解

    Spring MVC請求參數(shù)與響應(yīng)結(jié)果全局加密和解密詳解

    這篇文章主要給大家介紹了關(guān)于Spring MVC請求參數(shù)與響應(yīng)結(jié)果全局加密和解密的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Java泛型定義與用法實例詳解

    Java泛型定義與用法實例詳解

    這篇文章主要介紹了Java泛型定義與用法,結(jié)合實例形式較為詳細的分析了Java中泛型的概念、原理、定義、使用方法及相關(guān)操作注意事項,需要的朋友可以參考下
    2018-08-08

最新評論

石嘴山市| 长沙市| 湟中县| 镇赉县| 长岛县| 彭山县| 承德县| 余江县| 三台县| 玉田县| 昌图县| 乐平市| 靖安县| 丹寨县| 华安县| 泽普县| 五峰| 南平市| 东辽县| 镇平县| 广河县| 乌兰浩特市| 天镇县| 潞城市| 通海县| 桂阳县| 富裕县| 巴林右旗| 保亭| 宜宾县| 含山县| 正蓝旗| 澄江县| 调兵山市| 藁城市| 沅江市| 赤城县| 罗城| 隆回县| 皋兰县| 道真|