国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java多線程(4)---死鎖和Synchronized加鎖流程

這篇具有很好參考價值的文章主要介紹了Java多線程(4)---死鎖和Synchronized加鎖流程。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

前言

一.synchronized

1.1概念?

1.2Synchronized是什么鎖?

1.3Synchronized加鎖工作過程

1.4其他優(yōu)化操作

二.死鎖

2.1什么是死鎖

2.2死鎖的幾個經(jīng)典場景

2.3死鎖產(chǎn)生的條件

2.4如何解決死鎖


??個人主頁:tq02的博客_CSDN博客-C語言,Java,Java數(shù)據(jù)結(jié)構(gòu)領域博主
?? 本文由 tq02 原創(chuàng),首發(fā)于 CSDN??
???本章講解內(nèi)容:線程的策略鎖、CAS和JUC

Java多線程(4)---死鎖和Synchronized加鎖流程,JavaEE,java,開發(fā)語言,死鎖,java-ee

??多線程學習專欄:多線程學習專欄

??其他學習專欄:??C語言?? ? ? ??JavaSE?? ? ??MySQL基礎?

前言

? ? ? ? 在多線程的講解當中,我們可以知道synchronized是加鎖操作,讓兩個線程發(fā)生互斥效果,在代碼中使用synchronized關鍵字來實現(xiàn)鎖的獲取和釋放。如果是剛剛接觸多線程的人,我希望你可以從第一章多線程開始學習:http://t.csdn.cn/0vEhY

一.synchronized

1.1概念?

????????Synchronized是Java中內(nèi)置的鎖機制,用于實現(xiàn)線程同步。它可以通過在代碼中使用synchronized關鍵字來實現(xiàn)鎖的獲取和釋放。Synchronized關鍵字可以用在方法上或者代碼塊中。當一個線程執(zhí)行到synchronized修飾的代碼塊時,它會嘗試獲取鎖,如果鎖沒有被其他線程占用,則獲取成功,執(zhí)行代碼塊中的內(nèi)容。如果鎖已經(jīng)被其他線程占用,則該線程會進入等待狀態(tài),直到獲取到鎖才能繼續(xù)執(zhí)行。

1.2Synchronized是什么鎖?

  1. 開始時是樂觀鎖, 如果鎖沖突頻繁, 就轉(zhuǎn)換為悲觀鎖.
  2. 開始是輕量級鎖實現(xiàn), 如果鎖被持有的時間較長, 就轉(zhuǎn)換成重量級鎖.
  3. 實現(xiàn)輕量級鎖的時候大概率用到的自旋鎖策略
  4. 是一種不公平鎖
  5. 是一種可重入鎖
  6. 不是讀寫鎖
    ?

注:需要使用公平鎖,建議使用ReentrantLock來實現(xiàn)。ReentrantLock提供了公平鎖和非公平鎖兩種模式,通過構(gòu)造函數(shù)的參數(shù)來指定鎖的模式。

1.3Synchronized加鎖工作過程

????????對于鎖資源只有一個或者兩個線程交替競爭的,仍然需要使用系統(tǒng)調(diào)用,無疑對CPU資源是極大的消耗。因此,在jdk1.6針對Synchronized加鎖進行了優(yōu)化。按對鎖的競爭程度劃分成:無鎖,偏向鎖,輕量級鎖,重量級鎖。簡單而言就是從無鎖-->重量級鎖。?

無鎖

當你添加了鎖時,如果編譯器認為不需要加鎖,會自動刪除,因此便是無鎖

偏向鎖

偏向鎖不是真的 "加鎖", 只是給對象頭中做一個 "偏向鎖的標記", 記錄這個鎖屬于哪個線程.
如果后續(xù)沒有其他線程來競爭該鎖, 那么就不用進行其他同步操作了(避免了加鎖解鎖的開銷)
如果后續(xù)有其他線程來競爭該鎖(剛才已經(jīng)在鎖對象中記錄了當前鎖屬于哪個線程了, 很容易識別當前申請鎖的線程是不是之前記錄的線程), 那就取消原來的偏向鎖狀態(tài), 進入一般的輕量級鎖狀態(tài).
注:相當于做個標記,相當于 "延遲加鎖" . 能不加鎖就不加鎖, 盡量避免不必要的加鎖開銷.

輕量級鎖
隨著其他線程進入競爭, 偏向鎖狀態(tài)被消除, 進入輕量級鎖狀態(tài)(自適應的自旋鎖).
此處的輕量級鎖就是通過 CAS 來實現(xiàn)

  1. 通過 CAS 檢查并更新一塊內(nèi)存 (比如 null => 該線程引用)
  2. 如果更新成功, 則認為加鎖成功
  3. 如果更新失敗, 則認為鎖被占用, 繼續(xù)自旋式的等待(并不放棄 CPU).

注:此處的自旋鎖不會一種持續(xù)進行,而是達到一定的時間/重試次數(shù), 就不再自旋了.

重量級鎖
????????如果鎖競爭進一步激烈, 自旋不能快速獲取到鎖狀態(tài), 就會膨脹為重量級鎖

此處的重量級鎖就是指用到內(nèi)核提供的 mutex .
具體流程:

  • 執(zhí)行加鎖操作, 先進入內(nèi)核態(tài).
  • 在內(nèi)核態(tài)判定當前鎖是否已經(jīng)被占用
  • 如果該鎖沒有占用, 則加鎖成功, 并切換回用戶態(tài).
  • 如果該鎖被占用, 則加鎖失敗. 此時線程進入鎖的等待隊列, 掛起. 等待被操作系統(tǒng)喚醒.
  • 經(jīng)歷了一系列的滄海桑田, 這個鎖被其他線程釋放了, 操作系統(tǒng)也想起了這個掛起的線程, 于是喚醒
  • 這個線程, 嘗試重新獲取鎖

1.4其他優(yōu)化操作

? ? ? ? 我們額外補充2個編譯器對鎖的優(yōu)化操作。鎖消除和鎖粗化

鎖消除

????????代碼中, 用到了 synchronized, 但其實沒有在多線程環(huán)境下. (例如 StringBuffer)

StringBuffer tq02 = new StringBuffer();
tq02.append("a");
tq02.append("b");
tq02.append("c");
tq02.append("d");

每個 append 的調(diào)用都會涉及加鎖和解鎖. 但如果只是在單線程中執(zhí)行這個代碼, 那么這些加
鎖解鎖操作是沒有必要的, 白白浪費了一些資源開銷.因此將鎖給優(yōu)化了。

鎖粗化

鎖的粗化是根據(jù)鎖的粒度:粗和細
Java多線程(4)---死鎖和Synchronized加鎖流程,JavaEE,java,開發(fā)語言,死鎖,java-ee

?實際開發(fā)過程中, 使用細粒度鎖, 是期望釋放鎖的時候其他線程能使用鎖.但可能并沒有其他線程來搶占這個鎖. 這種情況 JVM 就會自動把鎖粗化, 避免頻繁申請釋放鎖.
?

二.死鎖

2.1什么是死鎖

????????死鎖是指在多進程系統(tǒng)中,每個進程都在等待某個資源,而該資源又被其他進程占用,導致所有進程都無法繼續(xù)執(zhí)行的狀態(tài)。

例如:A、B、C、D和E去上廁所,A進入廁所并且鎖門,B.C.D等待,可是A剛剛進入廁所,因為特殊的原因,憑空轉(zhuǎn)移到了外面,A就得重新排隊,可是門還是鎖著的啊,因此導致了死鎖。

2.2死鎖的幾個經(jīng)典場景

經(jīng)典場景有:

  1. 一個線程,一把鎖
  2. 兩個線程,兩把鎖
  3. 多個線程,多把鎖

1.一個線程,一把鎖

? ? ? ? 一個線程連續(xù)被同一個加鎖兩次,如果是不可重入鎖,那么會是死鎖。

解析:我去上廁所,我把廁所門鎖住,再通過廁所的窗戶出去,然后再來上廁所,發(fā)現(xiàn)廁所鎖住了,就耐心等待,卻沒想過這是自己鎖的。

代碼實現(xiàn):

public class Counter {
        
   void increase() {       
     synchronize(this){
       increase()   //可以理解為翻窗逃走,第二次加鎖時,是鎖了的
    }
}

public static void main(String[] args) throws InterruptedException {
    final Counter counter = new Counter();
        Thread t1 = new Thread(() -> {
                counter.increase();
        });
            t1.start();
    }
}

2.兩個線程,兩把鎖

????????線程1先獲取鎖A,再嘗試獲取鎖B,同時,線程2先獲取鎖B,再嘗試獲取鎖A,此時兩個線程就會互相僵住,誰都獲取不到對方持有的鎖。

解析:我在汽車里,車鑰匙在我妻子手上,我出不來,我妻子在房間里,房間鑰匙在我手上,我妻子也出不來,導致雙方被鎖,導致死鎖。

代碼示例:

public class Test {
    public static void main(String[] args) {
        //2個鎖對象
        Object lockerA = new Object();
        Object lockerB = new Object();
 
        Thread t1 = new Thread(() -> {
            System.out.println("t1嘗試獲取鎖A");
            synchronized (lockerA){
                System.out.println("t1獲取到鎖A");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1嘗試獲取鎖B");
                synchronized (lockerB){
                    System.out.println("t1獲取到鎖B");
                }
            }
        });
        Thread t2 = new Thread(() -> {
            System.out.println("t2嘗試獲取鎖B");
            synchronized (lockerB){
                System.out.println("t2獲取到鎖B");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2嘗試獲取鎖A");
                synchronized (lockerA){
                    System.out.println("t2獲取到鎖A");
                }
            }
        });
 
        t1.start();
        t2.start();
    }
}

3.多個線程,多把鎖

? ? ? ? 很明顯啊,兩把鎖,兩個線程也有問題,更何況是多把鎖啊,在這方面最經(jīng)典的是"哲學家就餐問題"。

Java多線程(4)---死鎖和Synchronized加鎖流程,JavaEE,java,開發(fā)語言,死鎖,java-ee

如圖:火柴人是哲學家、紅線是筷子,每一個哲學家的左右都有一根筷子。規(guī)定,當有一根哲學家餓了,會先拿起左邊的筷子,然后再拿右邊的筷子,吃完了就放下筷子。

造成死鎖問題:每一個哲學家都餓了,然后都拿起了左邊的筷子,可是當拿右邊的筷子時,發(fā)現(xiàn)有其他人在使用,所以導致阻塞,然后一直等待別人吃飽放下筷子,可是每個人都在等待。

2.3死鎖產(chǎn)生的條件

死鎖產(chǎn)生需要四個條件:

  1. 互斥使用,即當資源被一個線程使用(占有)時,別的線程不能使用
  2. 不可搶占,資源請求者不能強制從資源占有者手中奪取資源,資源只能由資源占有者主動釋放。
  3. 請求和保持,即當資源請求者在請求其他的資源的同時保持對原有資源的占有。
  4. 循環(huán)等待,即存在一個等待隊列:P1占有P2的資源,P2占有P3的資源,P3占有P1的資源。這樣就形成了一個等待環(huán)路。

當上述四個條件都成立的時候,便形成死鎖。當然,死鎖的情況下如果打破上述任何一個條件,便可讓死鎖消失。
?

2.4如何解決死鎖

? ? ? ? 想沒有死鎖,那么我們可以從死鎖產(chǎn)生的條件入手,只有破壞其他一條就可以了。?互斥使用和不可搶占是鎖的基本特性,因此無法干預,但是請求和保持,也不可能改變,因為這是代碼執(zhí)行邏輯。因此只有循環(huán)等待,我們可以打破

????????為了解決死鎖問題,可以采取預防、避免、檢測和解除四種方法。

預防:通過設置某些限制條件,以防止死鎖的發(fā)生。

避免:系統(tǒng)在分配資源時根據(jù)資源的使用情況提前作出預測,從而避免死鎖的發(fā)生。

檢測:允許系統(tǒng)在運行過程中產(chǎn)生死鎖,但系統(tǒng)中有相應的管理模塊可以及時檢測出已經(jīng)產(chǎn)生的死鎖,并精確地確定與死鎖有關的進程和資源,然后采取適當措施清除系統(tǒng)中已經(jīng)產(chǎn)生的死鎖。

解除:當發(fā)現(xiàn)有進程死鎖后,立即解脫它從死鎖狀態(tài)中出來。常用的方法包括剝奪資源和撤銷進程。剝奪資源是從其他進程中剝奪足夠數(shù)量的資源給死鎖進程,以解除死鎖狀態(tài)。撤銷進程可以直接撤銷死鎖進程或撤銷代價最小的進程,直至有足夠的資源可用,從而消除死鎖狀態(tài)。


? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????---------------------懶惰的tq02文章來源地址http://www.zghlxwxcb.cn/news/detail-644636.html

到了這里,關于Java多線程(4)---死鎖和Synchronized加鎖流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【JavaEE】Java中復雜的Synchronized關鍵字

    【JavaEE】Java中復雜的Synchronized關鍵字

    目錄 ?一、synchronized的特性 (1)互斥 (2)刷新內(nèi)存 (3)可重入 二、synchronized的使用 (1)修飾普通方法 (2)修飾靜態(tài)方法 (3)修飾代碼塊 三、synchronized的鎖機制 (1)基本特點 (2)加鎖工作過程 1.偏向鎖 2.輕量級鎖 3.重量級鎖 (3)優(yōu)化操作 1.鎖消除 2.鎖粗化 四、

    2024年01月19日
    瀏覽(22)
  • 【后端面經(jīng)-Java】公平鎖和加鎖流程

    目錄 1. 公平鎖和非公平鎖 1.1 基本概念 1.2 ReentrantLock 的公平鎖和非公平鎖 2. 加鎖流程 2.1 ReentrantLock 和 AQS 的關系 2.2 公平鎖-加鎖流程 2.3 非公平鎖-加鎖流程 2.4 加鎖流程和性能的關系 3. 面試問題模擬 參考文獻 公平鎖:線程按照到來的先后順序,排隊等待使用資源。 非公平

    2024年02月11日
    瀏覽(14)
  • java線程-synchronized詳解

    java線程-synchronized詳解

    解決線程原子性問題,最常見的手段就是加鎖,Java提供了兩種加鎖的方式,一個synchronized隱式鎖,另外一個是通過J.U.C框架提供的Lock顯式加鎖。本文主要介紹一個Synchronized的實現(xiàn)方式。 synchronized解決的是多個線程之間訪問資源的同步性,synchronized 翻譯為中文的意思是

    2024年02月10日
    瀏覽(38)
  • Java多線程(二)——synchronized 詳解

    Java多線程(二)——synchronized 詳解

    目錄 1?volatile 1.1保證變量可見性 1.2 不能保證數(shù)據(jù)的原子性舉例 1.3?禁止JVM指令重排序 2 synchronized 2.1 概念及演進 2.2 對象鎖和類鎖 2.3 synchronized 的用法分類 2.4 synchronized 的用法詳解 2.5 synchronized總結(jié)+補充 3?synchronized 底層原理 3.1 synchronized 同步語句塊的情況

    2024年02月13日
    瀏覽(19)
  • Synchronized與Java線程的關系

    Synchronized與Java線程的關系

    ? Java多線程處理任務時,為了線程安全,通常會對共享資源進行加鎖,拿到鎖的線程才能進行訪問共享資源。而加鎖方式通過都是Synchronized鎖或者Lock鎖。 ? 那么多線程在協(xié)同工作的時候,線程狀態(tài)的變化都與鎖對象有關系。 ? Java采用synchronized、以互斥同步的方式

    2024年02月11日
    瀏覽(12)
  • java死鎖、線程狀態(tài)、線程通信、線程池

    java實現(xiàn)多線程: [1]繼承Thread類并重寫run方法 [2]實現(xiàn)Runnable接口 線程Thread中常用的方法: setName(): Thread.currentThread().getName(): ? static void sleep(); static void yield(): join(): setDeamon()設置后臺線程 線程安全問題: ---當多個線程共享同一個資源時,對該資源的操作就會出現(xiàn)線程安全問題。

    2024年02月13日
    瀏覽(24)
  • JavaEE之多線程編程:5. 死鎖(詳解?。。。? decoding=
  • Java關鍵字之synchronized詳解【Java多線程必備】

    Java關鍵字之synchronized詳解【Java多線程必備】

    點擊 ? Mr.綿羊的知識星球 ?解鎖更多優(yōu)質(zhì)文章。 目錄 一、介紹 二、特性 1. 線程安全 2. 互斥訪問 3. 可重入性 4. 內(nèi)置鎖 三、實現(xiàn)原理 四、和其他鎖比較 1. 優(yōu)點 2. 缺點 五、注意事項和最佳實踐 六、使用案例 1. 案例一 2. 案例二 ? ? synchronized是Java中最基本的同步機制之一,

    2024年01月24日
    瀏覽(21)
  • Java多線程篇(1)——深入分析synchronized

    Java多線程篇(1)——深入分析synchronized

    synchronized實現(xiàn)原理的由淺入深依次為 字節(jié)碼層面:monitorenter/monitorexit 指令 java對象層面: Mark Word 對象頭 JVM層面: CAS、自旋 、 ObjectMonitor(MESA管層模型:cxq,entryList,wait三個隊列) 操作系統(tǒng)層面: mutex 鎖 其中 mark word 對象頭如下圖: 說到鎖升級,我相信很多人都錯

    2024年02月09日
    瀏覽(16)
  • Java多線程編程中的線程死鎖

    Java多線程編程中的線程死鎖

    ? 在多線程編程中,線程死鎖是一種常見的問題,它發(fā)生在兩個或多個線程互相等待對方釋放資源的情況下,導致程序無法繼續(xù)執(zhí)行 。本文將介紹線程死鎖的概念、產(chǎn)生原因、示例以及如何預防和解決線程死鎖問題。 線程死鎖的概念 ? 線程死鎖是指兩個或多個線程被阻塞

    2024年02月12日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包