欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java并發(fā)編程必備之Synchronized關(guān)鍵字深入解析

 更新時間:2025年04月02日 16:46:06   作者:權(quán)^  
本文我們深入探索了Java中的Synchronized關(guān)鍵字,包括其互斥性和可重入性的特性,文章詳細(xì)介紹了Synchronized的三種使用方式:修飾代碼塊、修飾普通方法和修飾靜態(tài)方法,感興趣的朋友一起看看吧

一、前言

在Java多線程編程中,線程安全是非常重要的一個概念。為了防止多個線程同時訪問共享資源時出現(xiàn)數(shù)據(jù)不一致或其他競態(tài)條件問題,Java提供了synchronized關(guān)鍵字和監(jiān)視器鎖(Monitor Lock)機(jī)制。這個博客將深入探討synchronized的原理、使用場景以及與監(jiān)視器鎖的關(guān)系。

二、Synchronized關(guān)鍵字

synchronized是Java中的一個關(guān)鍵字,用于在多線程環(huán)境中控制對共享資源的訪問。當(dāng)一個線程執(zhí)行synchronized修飾的方法或代碼塊時,其他線程將無法訪問相同的資源,直到當(dāng)前線程釋放資源鎖。

2.1 Synchronized的特性

1. 互斥

Synchronized 會起到互斥效果, 某個線程執(zhí)行到某個對象的 synchronized 中時, 其他線程如果也執(zhí)行到同一個對象 synchronized 就會阻塞等待。

• 進(jìn)入 synchronized 修飾的代碼塊, 相當(dāng)于 加鎖
• 退出 synchronized 修飾的代碼塊, 相當(dāng)于 解鎖

   synchronized (locker){
                for (int i = 0; i < 5000; i++) {
                    count++;
                }
            }

synchronized用的鎖是存在Java對象頭里的。

可以粗略理解成, 每個對象在內(nèi)存中存儲的時候, 都存有一塊內(nèi)存表示當(dāng)前的 “鎖定” 狀態(tài)(類似于廁所
的 “有人/無人”)。
如果當(dāng)前是 “無人” 狀態(tài), 那么就可以使用, 使用時需要設(shè)為 “有人” 狀態(tài)。
如果當(dāng)前是 “有人” 狀態(tài), 那么其他人無法使用, 只能排隊。

理解 “阻塞等待”。
針對每?把鎖, 操作系統(tǒng)內(nèi)部都維護(hù)了?個等待隊列. 當(dāng)這個鎖被某個線程占有的時候, 其他線程嘗試
進(jìn)行加鎖, 就加不上了, 就會阻塞等待, ?直等到之前的線程解鎖之后, 由操作系統(tǒng)喚醒?個新的線程,
再來獲取到這個鎖.

注意:

• 上一個線程解鎖之后, 下一個線程并不是立即就能獲取到鎖。而是要靠操作系統(tǒng)來 “喚醒”. 這也就
是操作系統(tǒng)線程調(diào)度的一部分工作。
• 假設(shè)有 A B C 三個線程, 線程 A 先獲取到鎖, 然后 B 嘗試獲取鎖, 然后 C 再嘗試獲取鎖, 此時 B 和 C
都在阻塞隊列中排隊等待.。但是當(dāng) A 釋放鎖之后, 雖然 B 比 C 先來的, 但是 B 不一定就能獲取到鎖,
而是和 C 重新競爭, 并不遵守先來后到的規(guī)則。
synchronized的底層是使用操作系統(tǒng)的mutex lock實現(xiàn)的。

2. 可重入

synchronized 同步塊對同?條線程來說是可重入的,不會出現(xiàn)自己把自己鎖死的問題。

理解 “把自己鎖死”

?個線程沒有釋放鎖, 然后又嘗試再次加鎖。
第?次加鎖, 加鎖成功
lock();
第?次加鎖, 鎖已經(jīng)被占用, 阻塞等待
lock();
按照之前對于鎖的設(shè)定, 第二次加鎖的時候, 就會阻塞等待. 直到第一次的鎖被釋放, 才能獲取到第二
個鎖.。但是釋放第?個鎖也是由該線程來完成, 結(jié)果這個線程已經(jīng)躺平了, 啥都不想干了, 也就無法進(jìn)行解鎖操作. 這時候就會死鎖。

Java 中的 synchronized可重?鎖, 因此沒有上面的問題。

for (int i = 0; i < 50000; i++) {
 synchronized (locker) {
 synchronized (locker) {
             count++;
           }
      }
}

在可重入鎖的內(nèi)部, 包含了 “線程持有者” 和 “計數(shù)器” 兩個信息。
• 如果某個線程加鎖的時候, 發(fā)現(xiàn)鎖已經(jīng)被人占用, 但是恰好占用的正是自己, 那么仍然可以繼續(xù)獲取到鎖, 并讓計數(shù)器自增。
• 解鎖的時候計數(shù)器遞減為 0 的時候, 才真正釋放鎖. (才能被別的線程獲取到)

三、synchronized 的使用示例

synchronized 本質(zhì)上要修改指定對象的 “對象頭”。從使用角度來看,synchronized 也勢必要搭配?個具體的對象來使用。

3.1 修飾代碼塊: 明確指定鎖哪個對象

1.鎖任意對象

public class Synchrinized1 {
    private static int count;
    public static void main(String[] args) {
        Object locker=new Object();
        Thread t1=new Thread(()->{
            for (int i = 0; i <10000 ; i++) {
                synchronized (locker){
                    count++;//鎖任意對象
                }
            }
        });
    }
}

2.鎖當(dāng)前對象

public class Synchrinized1 {
    private static int count;
    public static void main(String[] args) {
        Object locker=new Object();
        Thread t1=new Thread(()->{
            for (int i = 0; i <10000 ; i++) {
                synchronized (this){
                    count++;//鎖當(dāng)前對象
                }
            }
        });
    }
}

3.2直接修飾普通方法

public class Synchronized2{
    public int count=0;
    synchronized public void methond(){
        count++;
    }
}

3.3 修飾靜態(tài)方法

public class Synchronized{
    public static int count=0;
   public static synchronized void methon(){
        count++;
    }
}

四 、監(jiān)視器鎖(Monitor Lock)

Monitor Lock(監(jiān)視器鎖)是一種高級同步機(jī)制,底層實現(xiàn)了synchronized關(guān)鍵字的功能。每個對象都關(guān)聯(lián)一個監(jiān)視器鎖,當(dāng)線程進(jìn)入synchronized塊時,線程會獲取該對象的監(jiān)視器鎖。

4.1 監(jiān)視器鎖的特點

  • 互斥性:同一時間只有一個線程可以持有監(jiān)視器鎖。
  • 可重入性:同一線程可以多次獲取已持有的監(jiān)視器鎖。
  • 鎖升級:從未鎖定狀態(tài)偏向鎖,再到輕量級鎖,最終升級為重量級鎖。

4.2 Synchronized的底層實現(xiàn)

synchronized關(guān)鍵字的實現(xiàn)依賴于JVM,而JVM底層使用了監(jiān)視器鎖(Monitor Lock)來實現(xiàn)線程的同步。

當(dāng)線程執(zhí)行synchronized代碼時,JVM會檢查是否已經(jīng)獲得了監(jiān)視器鎖:

  • 如果未加鎖,當(dāng)前線程會嘗試獲取鎖。
  • 如果已加鎖,當(dāng)前線程將被阻塞,直到鎖被釋放。

4.3 onitor Lock的狀態(tài)

一個監(jiān)視器鎖有以下四種狀態(tài):

  • 未鎖定狀態(tài):任何線程都可以競爭鎖。
  • 偏向鎖狀態(tài):只允許一個線程持有鎖,減少競爭。
  • 輕量級鎖狀態(tài):多個線程競爭鎖,但未發(fā)生旋轉(zhuǎn)或阻塞。
  • 重量級鎖狀態(tài):線程競爭激烈,鎖被線程阻塞等待。

4.4 Synchronized與ReentrantLock的比較

4.5 常見問題及解決方案

1. 避免過度同步

過度同步會降低并發(fā)性能,應(yīng)盡量縮小同步范圍。

2. 避免死鎖

死鎖是由于多個線程互相持有對方資源而導(dǎo)致的??梢酝ㄟ^如下方式避免:

  • 按順序加鎖:對多個鎖的加鎖順序進(jìn)行統(tǒng)一。
  • 避免嵌套鎖:減少嵌套使用鎖的場景。

3. 數(shù)據(jù)一致性問題

在單例模式或共享變量的場景中,必須確保所有修改共享資源的操作都在同步塊內(nèi)。

五、總結(jié)

通過本文,我們深入探索了Java中的Synchronized關(guān)鍵字,包括其互斥性和可重入性的特性。文章詳細(xì)介紹了Synchronized的三種使用方式:修飾代碼塊、修飾普通方法和修飾靜態(tài)方法。同時,我們還解析了監(jiān)視器鎖(Monitor Lock)的底層實現(xiàn),以及SynchronizedReentrantLock的對比。最后,文章總結(jié)了并發(fā)編程中常見問題的解決方案,如避免過度同步、防止死鎖和保持?jǐn)?shù)據(jù)一致性。本文旨在幫助開發(fā)者更好地理解和使用Synchronized,從而編寫出高效、安全的并發(fā)程序。

到此這篇關(guān)于Java并發(fā)編程必備之Synchronized關(guān)鍵字深入解析的文章就介紹到這了,更多相關(guān)Java Synchronized關(guān)鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java8的default方法詳細(xì)介紹

    Java8的default方法詳細(xì)介紹

    這篇文章主要介紹了Java8的default方法,詳細(xì)介紹了什么是default方法,在多繼承時的處理等,需要的朋友可以參考下
    2014-04-04
  • Java遞歸算法詳解(動力節(jié)點整理)

    Java遞歸算法詳解(動力節(jié)點整理)

    Java遞歸算法是基于Java語言實現(xiàn)的遞歸算法。遞歸算法對解決一大類問題很有效,它可以使算法簡潔和易于理解。接下來通過本文給大家介紹Java遞歸算法相關(guān)知識,感興趣的朋友一起學(xué)習(xí)吧
    2017-03-03
  • 5分鐘搞定java單例模式

    5分鐘搞定java單例模式

    單例模式(Singleton?Pattern)是?Java?中最簡單的設(shè)計模式之一。這種類型的設(shè)計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式,本文給大家介紹下java單例模式的相關(guān)知識,感興趣的朋友一起看看吧
    2022-03-03
  • 若依前后端打成一個JAR包部署的完整步驟

    若依前后端打成一個JAR包部署的完整步驟

    這篇文章主要介紹了如何將若依前后端分離項目打包成jar,不使用nginx轉(zhuǎn)發(fā),前端修改了路由模式和環(huán)境變量配置,后端增加了依賴、配置了Thymeleaf和訪問路徑,需要的朋友可以參考下
    2025-01-01
  • SpringBoot啟動時自動執(zhí)行指定方法的幾種實現(xiàn)方式

    SpringBoot啟動時自動執(zhí)行指定方法的幾種實現(xiàn)方式

    在Spring Boot應(yīng)用程序中,要實現(xiàn)在應(yīng)用啟動時自動執(zhí)行某些代碼,本文主要介紹了SpringBoot啟動時自動執(zhí)行指定方法的幾種方式,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2024-03-03
  • Sentinel中實現(xiàn)限流的兩種方法

    Sentinel中實現(xiàn)限流的兩種方法

    本文給大家介紹了Sentinel中實現(xiàn)限流的兩種方法,限流是一種通過控制系統(tǒng)對外提供的資源、服務(wù)或接口的訪問數(shù)量或速率,以保護(hù)系統(tǒng)免受過載的一種策略,需要的朋友可以參考下
    2024-02-02
  • SpringBoot日志進(jìn)階實戰(zhàn)之Logback配置經(jīng)驗和方法

    SpringBoot日志進(jìn)階實戰(zhàn)之Logback配置經(jīng)驗和方法

    本文給大家介紹在SpringBoot中使用Logback配置日志的經(jīng)驗和方法,并提供了詳細(xì)的代碼示例和解釋,包括:滾動文件、異步日志記錄、動態(tài)指定屬性、日志級別、配置文件等常用功能,覆蓋日常Logback配置開發(fā)90%的知識點,感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • SpringBoot學(xué)習(xí)之Json數(shù)據(jù)交互的方法

    SpringBoot學(xué)習(xí)之Json數(shù)據(jù)交互的方法

    這篇文章主要介紹了SpringBoot學(xué)習(xí)之Json數(shù)據(jù)交互的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • java反射耗時測試案例解析

    java反射耗時測試案例解析

    這篇文章主要介紹了java反射耗時測試案例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • Java中StringBuilder類的介紹與常用方法

    Java中StringBuilder類的介紹與常用方法

    StringBuilder是一個可變的字符串的操作類,我們可以把它看成是一個對象容器,下面這篇文章主要給大家介紹了關(guān)于Java中StringBuilder類的介紹與常用方法,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12

最新評論