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

Java中Synchronized鎖的使用和原理詳解

 更新時(shí)間:2023年07月26日 09:35:07   作者:「已注銷」  
這篇文章主要介紹了Java中Synchronized鎖的使用和原理詳解,synchronized是?Java?內(nèi)置的關(guān)鍵字,它提供了一種獨(dú)占的加鎖方式,synchronized的獲取和釋放鎖由JVM實(shí)現(xiàn),用戶不需要顯示的釋放鎖,非常方便,需要的朋友可以參考下

Synchronized 鎖的使用和原理

Synchronized是java的一個(gè)關(guān)鍵字,加鎖方式有: 對(duì)象鎖、類鎖

其用法有:

  • 普通同步方法,鎖是當(dāng)前實(shí)例對(duì)象
  • 靜態(tài)同步方法,鎖是當(dāng)前類的class對(duì)象
  • 同步方法塊,鎖是括號(hào)里面的對(duì)象

Synchronized的使用

對(duì)象鎖

方法鎖: 默認(rèn)所對(duì)象為this,當(dāng)前實(shí)例對(duì)象

public class SynchronizedMethodLock implements Runnable{
    static SynchronizedMethodLock instence = new SynchronizedMethodLock();
    @Override
    public void run() {
        method();
    }
    public synchronized void method() {
        System.out.println("我是線程" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "結(jié)束");
    }
    public static void main(String[] args) {
        Thread thread1 = new Thread(instence);
        Thread thread2 = new Thread(instence);
        thread1.start();
        thread2.start();
    }
}

同步代碼塊鎖: 手動(dòng)指定鎖定對(duì)象(this或者自定義鎖)

  • this
public class SynchronizedThisLock implements Runnable{
    static SynchronizedThisLock instence = new SynchronizedThisLock();
    @Override
    public void run() {
        // 同步代碼塊形式——鎖為this,兩個(gè)線程使用的鎖是一樣的,線程1必須要等到線程0釋放了該鎖后,才能執(zhí)行
        synchronized (this) {
            System.out.println("我是線程" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "結(jié)束");
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence);
        Thread t2 = new Thread(instence);
        t1.start();
        t2.start();
    }
}
  • 自定義對(duì)象
public class SynchronizedObjectLock implements Runnable{
    static SynchronizedObjectLock instence = new SynchronizedObjectLock();
    // 創(chuàng)建2把鎖
    Object block1 = new Object();
    Object block2 = new Object();
    @Override
    public void run() {
        // 這個(gè)代碼塊使用的是第一把鎖,當(dāng)他釋放后,后面的代碼塊由于使用的是第二把鎖,因此可以馬上執(zhí)行
        synchronized (block1) {
            System.out.println("block1鎖,我是線程" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("block1鎖,"+Thread.currentThread().getName() + "結(jié)束");
        }
        synchronized (block2) {
            System.out.println("block2鎖,我是線程" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("block2鎖,"+Thread.currentThread().getName() + "結(jié)束");
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence);
        Thread t2 = new Thread(instence);
        t1.start();
        t2.start();
    }
}

類鎖

synchronized修飾靜態(tài)方法或指定鎖對(duì)象為Class對(duì)象

public class SynchronizedClassLock implements Runnable{
    static SynchronizedObjectLock instence1 = new SynchronizedObjectLock();
    static SynchronizedObjectLock instence2 = new SynchronizedObjectLock();
    @Override
    public void run() {
        // 所有線程需要的鎖都是同一把
        synchronized(SynchronizedClassLock.class){
            System.out.println("我是線程" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "結(jié)束");
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence1);
        Thread t2 = new Thread(instence2);
        t1.start();
        t2.start();
    }
}
public class SynchronizedStaticMethodLock implements Runnable{
    static SynchronizedStaticMethodLock instence1 = new SynchronizedStaticMethodLock();
    static SynchronizedStaticMethodLock instence2 = new SynchronizedStaticMethodLock();
    @Override
    public void run() {
        method();
    }
    public static synchronized void method() {
        // 所有線程需要的鎖都是同一把
        System.out.println("我是線程" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "結(jié)束");
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence1);
        Thread t2 = new Thread(instence2);
        t1.start();
        t2.start();
    }
}

synchronized原理

synchronized枷鎖和釋放鎖是基于monitorentermonitorexit指令實(shí)現(xiàn)的

MonitorenterMonitorexit指令,會(huì)讓對(duì)象在執(zhí)行,使其鎖計(jì)數(shù)器加1或者減1。每一個(gè)對(duì)象在同一時(shí)間只與一個(gè)monitor(鎖)相關(guān)聯(lián),而一個(gè)monitor在同一時(shí)間只能被一個(gè)線程獲得,一個(gè)對(duì)象在嘗試獲得與這個(gè)對(duì)象相關(guān)聯(lián)的Monitor鎖的所有權(quán)的時(shí)候,

monitorenter指令

  • monitor計(jì)數(shù)器為0,意味著目前還沒有被獲得,那這個(gè)線程就會(huì)立刻獲得然后把鎖計(jì)數(shù)器+1,一旦+1,別的線程再想獲取,就需要等待
  • 如果這個(gè)monitor已經(jīng)拿到了這個(gè)鎖的所有權(quán),又重入了這把鎖,那鎖計(jì)數(shù)器就會(huì)累加,變成2,并且隨著重入的次數(shù),會(huì)一直累加
  • 這把鎖已經(jīng)被別的線程獲取了,等待鎖釋放

monitorexit指令:釋放對(duì)于monitor的所有權(quán),釋放過程很簡(jiǎn)單,就是講monitor的計(jì)數(shù)器減1,如果減完以后,計(jì)數(shù)器不是0,則代表剛才是重入進(jìn)來(lái)的,當(dāng)前線程還繼續(xù)持有這把鎖的所有權(quán),如果計(jì)數(shù)器變成0,則代表當(dāng)前線程不再擁有該monitor的所有權(quán),即釋放鎖。

JVM中鎖的優(yōu)化

簡(jiǎn)單來(lái)說(shuō)在JVM中monitorentermonitorexit字節(jié)碼依賴于底層的操作系統(tǒng)的Mutex Lock來(lái)實(shí)現(xiàn)的,但是由于使用Mutex Lock需要將當(dāng)前線程掛起并從用戶態(tài)切換到內(nèi)核態(tài)來(lái)執(zhí)行,這種切換的代價(jià)是非常昂貴的;然而在現(xiàn)實(shí)中的大部分情況下,同步方法是運(yùn)行在單線程環(huán)境(無(wú)鎖競(jìng)爭(zhēng)環(huán)境)如果每次都調(diào)用Mutex Lock那么將嚴(yán)重的影響程序的性能。不過在jdk1.6中對(duì)鎖的實(shí)現(xiàn)引入了大量的優(yōu)化,如鎖粗化(Lock Coarsening)、鎖消除(Lock Elimination)、輕量級(jí)鎖(Lightweight Locking)、偏向鎖(Biased Locking)、適應(yīng)性自旋(Adaptive Spinning)等技術(shù)來(lái)減少鎖操作的開銷。

  • 鎖粗化(Lock Coarsening):也就是減少不必要的緊連在一起的unlock,lock操作,將多個(gè)連續(xù)的鎖擴(kuò)展成一個(gè)范圍更大的鎖。
  • 鎖消除(Lock Elimination):通過運(yùn)行時(shí)JIT編譯器的逃逸分析來(lái)消除一些沒有在當(dāng)前同步塊以外被其他線程共享的數(shù)據(jù)的鎖保護(hù),通過逃逸分析也可以在線程本的Stack上進(jìn)行對(duì)象空間的分配(同時(shí)還可以減少Heap上的垃圾收集開銷)。
  • 輕量級(jí)鎖(Lightweight Locking):這種鎖實(shí)現(xiàn)的背后基于這樣一種假設(shè),即在真實(shí)的情況下我們程序中的大部分同步代碼一般都處于無(wú)鎖競(jìng)爭(zhēng)狀態(tài)(即單線程執(zhí)行環(huán)境),在無(wú)鎖競(jìng)爭(zhēng)的情況下完全可以避免調(diào)用操作系統(tǒng)層面的重量級(jí)互斥鎖,取而代之的是在monitorenter和monitorexit中只需要依靠一條CAS原子指令就可以完成鎖的獲取及釋放。當(dāng)存在鎖競(jìng)爭(zhēng)的情況下,執(zhí)行CAS指令失敗的線程將調(diào)用操作系統(tǒng)互斥鎖進(jìn)入到阻塞狀態(tài),當(dāng)鎖被釋放的時(shí)候被喚醒(具體處理步驟下面詳細(xì)討論)。
  • 偏向鎖(Biased Locking):是為了在無(wú)鎖競(jìng)爭(zhēng)的情況下避免在鎖獲取過程中執(zhí)行不必要的CAS原子指令,因?yàn)镃AS原子指令雖然相對(duì)于重量級(jí)鎖來(lái)說(shuō)開銷比較小但還是存在非??捎^的本地延遲。
  • 適應(yīng)性自旋(Adaptive Spinning):當(dāng)線程在獲取輕量級(jí)鎖的過程中執(zhí)行CAS操作失敗時(shí),在進(jìn)入與monitor相關(guān)聯(lián)的操作系統(tǒng)重量級(jí)鎖(mutex semaphore)前會(huì)進(jìn)入忙等待(Spinning)然后再次嘗試,當(dāng)嘗試一定的次數(shù)后如果仍然沒有成功則調(diào)用與該monitor關(guān)聯(lián)的semaphore(即互斥鎖)進(jìn)入到阻塞狀態(tài)。
  • 樂觀鎖:是一種樂觀思想,即認(rèn)為讀多寫少,遇到并發(fā)寫的可能性低,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù),采取在寫時(shí)先讀出當(dāng)前版本號(hào),然后加鎖操作(比較跟上一次的版本號(hào),如果一樣則更新),如果失敗則要重復(fù)讀-比較-寫的操作。java中的樂觀鎖基本都是通過CAS操作實(shí)現(xiàn)的,CAS是一種更新的原子操作,比較當(dāng)前值跟傳入值是否一樣,一樣則更新,否則失敗。
  • 悲觀鎖:就是悲觀思想,即認(rèn)為寫多,遇到并發(fā)寫的可能性高,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在讀寫數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想讀寫這個(gè)數(shù)據(jù)就會(huì)block直到拿到鎖。java中的悲觀鎖就是Synchronized,AQS框架下的鎖則是先嘗試cas樂觀鎖去獲取鎖,獲取不到,才會(huì)轉(zhuǎn)換為悲觀鎖,如RetreenLock。

synchronized鎖升級(jí)過程

鎖的級(jí)別從低到高逐步升級(jí)

無(wú)鎖->偏向鎖->輕量級(jí)鎖->重量級(jí)鎖

到此這篇關(guān)于Java中Synchronized鎖的使用和原理詳解的文章就介紹到這了,更多相關(guān)Java中Synchronized鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis返回值(resultType&resultMap)的具體使用

    Mybatis返回值(resultType&resultMap)的具體使用

    返回值屬性有兩種設(shè)置,一種是resultType,一種是resultMap,本文主要介紹了Mybatis返回值(resultType&resultMap)的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • JVM(Java虛擬機(jī))簡(jiǎn)介(動(dòng)力節(jié)點(diǎn)Java學(xué)院整理)

    JVM(Java虛擬機(jī))簡(jiǎn)介(動(dòng)力節(jié)點(diǎn)Java學(xué)院整理)

    Java虛擬機(jī)(Jvm)是可運(yùn)行Java代碼的假想計(jì)算機(jī)。Java虛擬機(jī)包括一套字節(jié)碼指令集、一組寄存器、一個(gè)棧、一個(gè)垃圾回收堆和一個(gè)存儲(chǔ)方法域。對(duì)java jvm 虛擬機(jī)感興趣的朋友通過本文一起學(xué)習(xí)吧
    2017-04-04
  • jvm調(diào)優(yōu)常用命令行工具詳解

    jvm調(diào)優(yōu)常用命令行工具詳解

    這篇文章主要介紹了jvm調(diào)優(yōu)常用命令行工具的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • SpringBoot 中使用RabbtiMq?詳解

    SpringBoot 中使用RabbtiMq?詳解

    這篇文章主要介紹了SpringBoot 中使用RabbtiMq詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)價(jià)值,需要的朋友可以參考一下
    2022-07-07
  • mybatis?對(duì)于生成的sql語(yǔ)句?自動(dòng)加上單引號(hào)的情況詳解

    mybatis?對(duì)于生成的sql語(yǔ)句?自動(dòng)加上單引號(hào)的情況詳解

    這篇文章主要介紹了mybatis?對(duì)于生成的sql語(yǔ)句?自動(dòng)加上單引號(hào)的情況詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • IDEA Maven依賴下載總是失敗的幾種解決方法

    IDEA Maven依賴下載總是失敗的幾種解決方法

    我們本地使用 IDEA 運(yùn)行 maven 項(xiàng)目的時(shí)候,有時(shí)候運(yùn)氣不好,就會(huì)遇到某些 maven 依賴無(wú)法正常找到、導(dǎo)入,這就會(huì)導(dǎo)致 IDEA 構(gòu)建項(xiàng)目的時(shí)候爆出一堆醒目的紅色 Error,今天給大家分享IDEA Maven依賴下載總是失敗的幾種解決方法,感興趣的朋友一起看看吧
    2023-09-09
  • spring?boot中spring框架的版本升級(jí)圖文教程

    spring?boot中spring框架的版本升級(jí)圖文教程

    Spring Boot是一款基于Spring框架的快速開發(fā)框架,它提供了一系列的開箱即用的功能和組件,這篇文章主要給大家介紹了關(guān)于spring?boot中spring框架的版本升級(jí)的相關(guān)資料,需要的朋友可以參考下
    2023-10-10
  • Java使用Runnable接口創(chuàng)建線程的示例代碼

    Java使用Runnable接口創(chuàng)建線程的示例代碼

    在Java中,多線程編程是實(shí)現(xiàn)并發(fā)操作的重要手段之一,通過多線程,程序可以同時(shí)執(zhí)行多個(gè)任務(wù),從而提高應(yīng)用程序的效率和響應(yīng)速度,Java提供了多種創(chuàng)建線程的方式,其中實(shí)現(xiàn)Runnable接口是最常見且推薦的方式之一,本文將詳細(xì)介紹如何使用Runnable接口創(chuàng)建線程
    2025-02-02
  • Java日常開發(fā)中讀寫TXT文本舉例詳解

    Java日常開發(fā)中讀寫TXT文本舉例詳解

    這篇文章主要給大家介紹了關(guān)于Java日常開發(fā)中讀寫TXT文本,包括使用BufferedReader、Scanner、FileInputStream等類進(jìn)行讀取,以及使用BufferedWriter、PrintWriter、FileOutputStream等類進(jìn)行寫入,需要的朋友可以參考下
    2024-12-12
  • Java中輸入輸出方式詳細(xì)講解

    Java中輸入輸出方式詳細(xì)講解

    這篇文章主要給大家介紹了關(guān)于Java中輸入輸出方式的相關(guān)資料,Java輸入輸出是指使用java提供的一些類和方法來(lái)實(shí)現(xiàn)數(shù)據(jù)的輸入和輸出,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09

最新評(píng)論