日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

无招胜有招之锁

發(fā)布時間:2024/2/28 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 无招胜有招之锁 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、CAS、樂觀鎖與悲觀鎖、數(shù)據(jù)庫相關(guān)鎖機制、分布式鎖、偏向鎖、輕量級鎖、重量級鎖、Monitor

CAS:在java并發(fā)應用中通常指CompareAndSwap或CompareAndSet,即比較并交換。

簡單來說就是一種無鎖算法,有三個操作數(shù)(內(nèi)存值V,舊的預期值A(chǔ),要修改的新值B。當且僅當A=V,將V修改為B否則什么都不做。)

  • CAS是一個原子操作,它比較一個內(nèi)存位置的值并且只有相等時修改這個內(nèi)存位置的值為新值,保證新的值總是基于最新的信息計算,如果有其他線程在這期間修改了這個值則CAS失敗。CAS返回是否成功或者內(nèi)存位置原來的值用于判斷是否CAS成功。
  • JVM中的CAS操作是利用了處理器提供的CMPXCHG指令實現(xiàn)的。優(yōu)點:競爭不大時系統(tǒng)開銷小。缺點:循環(huán)時間長開銷大、只能保證一個共享變量的原子操作、ABA的問題
  • 樂觀鎖與悲觀鎖

    1.樂觀鎖:總是假設最好的情況,每次去拿數(shù)據(jù)的時候都認為別人不會修改,所以不會上鎖。但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù),可以使用版本號機制和CAS算法實現(xiàn)。

    2.悲觀鎖:總是假設最壞的情況,每次去拿數(shù)據(jù)的時候都認為別人會修改,所以每次在拿數(shù)據(jù)時都會上鎖,這樣別人想拿這個數(shù)據(jù)時就會阻塞,直到他拿到鎖(共享資源每次只給一個線程使用,用完后再把資源轉(zhuǎn)讓給其他線程。)

    數(shù)據(jù)庫相關(guān)鎖機制:

    數(shù)據(jù)庫鎖一般分為兩類,一個是悲觀鎖,一個是樂觀鎖。

    樂觀鎖一般是指用戶自己實現(xiàn)的一種鎖機制,悲觀鎖一般就是我們通常說的數(shù)據(jù)庫鎖機制,悲觀鎖主要表鎖、行鎖、頁鎖

    分布式鎖:

    分布式鎖是控制分布式系統(tǒng)之間同步訪問共享資源的一種方式。

    分布式應該具備些條件:

  • 在分布式系統(tǒng)環(huán)境下,一個方法在同一時間只能被一個機器的一個線程執(zhí)行;?
    2、高可用的獲取鎖與釋放鎖;?
    3、高性能的獲取鎖與釋放鎖;?
    4、具備可重入特性;?
    5、具備鎖失效機制,防止死鎖;?
    6、具備非阻塞鎖特性,即沒有獲取到鎖將直接返回獲取鎖失敗。
  • 分布式鎖的三種實現(xiàn)方式:

  • 基于數(shù)據(jù)庫實現(xiàn)分布式鎖;?
    2.基于緩存(Redis等)實現(xiàn)分布式鎖;?
    3.基于Zookeeper實現(xiàn)分布式鎖;
  • 偏向鎖:

    在沒有實際競爭的情況下,還能夠針對部分場景繼續(xù)優(yōu)化。如果不僅僅沒有實際競爭,自始至終,使用鎖的線程都只有一個,那么,維護輕量級鎖都是浪費的。偏向鎖的目標是,減少無競爭且只有一個線程使用鎖的情況下,使用輕量級鎖產(chǎn)生的性能消耗。輕量級鎖每次申請、釋放鎖都至少需要一次CAS,但偏向鎖只有初始化時需要一次CAS。

    “偏向”的意思是,偏向鎖假定將來只有第一個申請鎖的線程會使用鎖(不會有任何線程再來申請鎖),因此,只需要在Mark Word中CAS記錄owner(本質(zhì)上也是更新,但初始值為空),如果記錄成功,則偏向鎖獲取成功,記錄鎖狀態(tài)為偏向鎖,以后當前線程等于owner就可以零成本的直接獲得鎖;否則,說明有其他線程競爭,膨脹為輕量級鎖。

    偏向鎖無法使用自旋鎖優(yōu)化,因為一旦有其他線程申請鎖,就破壞了偏向鎖的假定。

    缺點

    同樣的,如果明顯存在其他線程申請鎖,那么偏向鎖將很快膨脹為輕量級鎖。

    輕量級鎖:

    自旋鎖的目標是降低線程切換的成本。如果鎖競爭激烈,我們不得不依賴于重量級鎖,讓競爭失敗的線程阻塞;如果完全沒有實際的鎖競爭,那么申請重量級鎖都是浪費的。輕量級鎖的目標是,減少無實際競爭情況下,使用重量級鎖產(chǎn)生的性能消耗,包括系統(tǒng)調(diào)用引起的內(nèi)核態(tài)與用戶態(tài)切換、線程阻塞造成的線程切換等。

    顧名思義,輕量級鎖是相對于重量級鎖而言的。使用輕量級鎖時,不需要申請互斥量,僅僅將Mark Word中的部分字節(jié)CAS更新指向線程棧中的Lock Record,如果更新成功,則輕量級鎖獲取成功,記錄鎖狀態(tài)為輕量級鎖;否則,說明已經(jīng)有線程獲得了輕量級鎖,目前發(fā)生了鎖競爭(不適合繼續(xù)使用輕量級鎖),接下來膨脹為重量級鎖。

    Mark Word是對象頭的一部分;每個線程都擁有自己的線程棧(虛擬機棧),記錄線程和函數(shù)調(diào)用的基本信息。二者屬于JVM的基礎(chǔ)內(nèi)容,此處不做介紹。

    當然,由于輕量級鎖天然瞄準不存在鎖競爭的場景,如果存在鎖競爭但不激烈,仍然可以用自旋鎖優(yōu)化,自旋失敗后再膨脹為重量級鎖。

    缺點

    同自旋鎖相似,如果鎖競爭激烈,那么輕量級將很快膨脹為重量級鎖,那么維持輕量級鎖的過程就成了浪費。

    重量級鎖:

    內(nèi)置鎖(內(nèi)置鎖是JVM提供的最便捷的線程同步工具,在代碼塊或方法聲明上添加synchronized關(guān)鍵字即可使用內(nèi)置鎖)在Java中被抽象為監(jiān)視器鎖(monitor)。在JDK 1.6之前,監(jiān)視器鎖可以認為直接對應底層操作系統(tǒng)中的互斥量(mutex)。這種同步方式的成本非常高,包括系統(tǒng)調(diào)用引起的內(nèi)核態(tài)與用戶態(tài)切換、線程阻塞造成的線程切換等。因此,后來稱這種鎖為“重量級鎖”。

    偏向鎖、輕量級鎖、重量級鎖適用于不同的并發(fā)場景:

    偏向鎖:無實際競爭,且將來只有第一個申請鎖的線程會使用鎖。

    輕量級鎖:無實際競爭,多個線程交替使用鎖;允許短時間的鎖競爭。

    重量級鎖:有實際競爭,且鎖競爭時間長。

    另外,如果鎖競爭時間短,可以使用自旋鎖進一步優(yōu)化輕量級鎖、重量級鎖的性能,減少線程切換。

    如果鎖競爭程度逐漸提高(緩慢),那么從偏向鎖逐步膨脹到重量鎖,能夠提高系統(tǒng)的整體性能

    二、鎖優(yōu)化、鎖消除、鎖粗化、自旋鎖、可重入鎖、阻塞鎖、死鎖:

    1.鎖優(yōu)化:減少鎖的持有時間(將同步方法改成同步代碼塊)、減少鎖的粒度(ConcurrentHashMap)、讀寫分離鎖代替獨占鎖(ReadWriterLock)、鎖分離(LinkedBlockingQueue)、鎖粗化。推薦https://www.cnblogs.com/xdecode/p/9137804.html

    2.鎖消除:指虛擬機即時編譯器在運行時,對一些代碼上要求同步,但是被檢測到不可能存在共享數(shù)據(jù)競爭的鎖進行削除。然后帶來一定的性能提升。

    3.鎖粗化:通常情況下,為了保證多線程間的有效并發(fā),會要求每個線程持有鎖的時間盡可能短,但是大某些情況下,一個程序?qū)ν粋€鎖不間斷、高頻地請求、同步與釋放,會消耗掉一定的系統(tǒng)資源,因為鎖的講求、同步與釋放本身會帶來性能損耗,這樣高頻的鎖請求就反而不利于系統(tǒng)性能的優(yōu)化了,雖然單次同步操作的時間可能很短。鎖粗化就是告訴我們?nèi)魏问虑槎加袀€度,有些情況下我們反而希望把很多次鎖的請求合并成一個請求,以降低短時間內(nèi)大量鎖請求、同步、釋放帶來的性能損耗。

    4.自旋鎖:又稱非可重入鎖。簡單來說,若一個類中有兩個方法A、B,則AB都有獲得同一把鎖,||當A調(diào)用時獲得鎖,在A方法鎖還沒有被釋放時,調(diào)用B時,B無法獲得鎖。必須等A釋放鎖。首先,內(nèi)核態(tài)與用戶態(tài)的切換上不容易優(yōu)化。但通過自旋鎖,可以減少線程阻塞造成的線程切換(包括掛起線程和恢復線程)。因為鎖阻塞造成線程切換的時間與鎖持有的時間相當,所以減少線程阻塞造成的線程切換,就能得到較大的性能提升。

    推薦:https://www.jianshu.com/p/36eedeb3f912

    5.可重入鎖:簡單來說,若一個類中有兩個方法A、B,則AB都有獲得同一把鎖,||當A調(diào)用時獲得鎖,在A方法鎖還沒有被釋放時,調(diào)用B時,B也獲得鎖。專業(yè)說法:又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,再進入該線程的內(nèi)層方法會自動獲取鎖(前提鎖對象得是同一個對象或者class),不會因為之前已經(jīng)獲取過還沒釋放而阻塞。Java中ReentrantLock和synchronized都是可重入鎖,可重入鎖的一個優(yōu)點是可一定程度避免死鎖。

    6.阻塞鎖:阻塞鎖指改變了線程的運行狀態(tài),在java中,線程Thread有如下幾種狀態(tài):新建狀態(tài)、就緒狀態(tài)、運行狀態(tài)、阻塞狀態(tài)、死亡狀態(tài)。阻塞鎖,可以說是讓線程進入阻塞狀態(tài)進行等待,當獲得相應的信號(喚醒,時間) 時,才可以進入線程的準備就緒狀態(tài),準備就緒狀態(tài)的所有線程,通過競爭,進入運行狀態(tài)。

    7.死鎖:不同線程分別占用對方需要的同步資源不放棄,都在等待對方放棄自己需要的同步資源,就形成了線程的死鎖。

    三、死鎖的原因

  • 競爭資源引起進程死鎖
  • 競爭不可剝奪資源(可剝奪資源和不可剝奪資源)
  • 競爭臨時資源
  • 進程推進順序不當引起死鎖
  • 四、死鎖的解決辦法:

  • 死鎖預防。去破壞產(chǎn)生死鎖的四個必要條件(互斥、占有且等待、不可搶占、循環(huán)等待)中的一個或者幾個,來預防發(fā)生死鎖。
  • 死鎖避免。在使用前進行判斷,只允許不會產(chǎn)生死鎖的進程申請資源
  • 死鎖檢測和解除。在檢測到運行系統(tǒng)進入死鎖,進行恢復。
    • CountDownLatch、 CyclicBarrier 和Semaphore三個類的使用和原理:

    JAVA并發(fā)包中有三個類用于同步一批線程的行為,分別是CountDownLatch、Semaphore和CyclicBarrier。

    1.CountDownLatch是一個計數(shù)器閉鎖,通過它可以完成類似于阻塞當前線程的功能,即:一個線程或多個線程一直等待,直到其他線程執(zhí)行的操作完成。CountDownLatch用一個給定的計數(shù)器來初始化,該計數(shù)器的操作是原子操作,即同時只能有一個線程去操作該計數(shù)器。

    2.Semaphore與CountDownLatch相似,不同的地方在于Semaphore的值被獲取到后是可以釋放的,并不像CountDownLatch那樣一直減到底。它也被更多地用來限制流量,類似閥門的 功能。如果限定某些資源最多有N個線程可以訪問,那么超過N個主不允許再有線程來訪問,同時當現(xiàn)有線程結(jié)束后,就會釋放,然后允許新的線程進來。有點類似于鎖的lock與 unlock過程。相對來說他也有兩個主要的方法:

    用于獲取權(quán)限的acquire(),其底層實現(xiàn)與CountDownLatch.countdown()類似;
    用于釋放權(quán)限的release(),其底層實現(xiàn)與acquire()是一個互逆的過程。

    推薦:https://www.jianshu.com/p/bb5105303d85

    3.CyclicBarrier也是一個同步輔助類,它允許一組線程相互等待,直到到達某個公共屏障點(common barrier point)。通過它可以完成多個線程之間相互等待,只有當每個線程都準備就緒后,才能各自繼續(xù)往下執(zhí)行后面的操作。類似于CountDownLatch,它也是通過計數(shù)器來實現(xiàn)的。那么CyclicBarrier和CountDownLatch之間的區(qū)別在于:

    CountDownLatch主要是實現(xiàn)了1個或N個線程需要等待其他線程完成某項操作之后才能繼續(xù)往下執(zhí)行操作,描述的是1個線程或N個線程等待其他線程的關(guān)系。CyclicBarrier主要是實現(xiàn)了多個線程之間相互等待,直到所有的線程都滿足了條件之后各自才能繼續(xù)執(zhí)行后續(xù)的操作,描述的多個線程內(nèi)部相互等待的關(guān)系。

    CountDownLatch是一次性的,而CyclicBarrier則可以被重置而重復使用。

    總結(jié)

    以上是生活随笔為你收集整理的无招胜有招之锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。