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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

常见锁的概念

發(fā)布時間:2024/9/30 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 常见锁的概念 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

常見的鎖的概念

  • 可重入鎖
  • 公平鎖/非公平鎖
  • 獨享鎖/共享鎖
  • 互斥鎖/讀寫鎖
  • 樂觀鎖/悲觀鎖
  • 分段鎖
  • 偏向鎖/輕量級鎖/重量級鎖
  • 自旋鎖
  • 修改 使用鎖 或者同步機制
    僅僅給變量添加volatile 是不行的 還會出現(xiàn)多賣少買狀況
    synchronized 簡介 :非常經(jīng)典的處理手段,具體使用有多種形式,它的核心思想就是修飾一個方法或者一段代碼,這段代碼不能同時兩個以上的線程同時運行。
    代碼塊 中的this 是調(diào)用該方法的對象 一般都是使用代碼塊
    理解一下synchronized 直譯過來 是同步的意思 但是我們京城稱呼其為一種鎖,為什么叫鎖,原則上每個對象都可以持有一把鎖,當(dāng)某一個線程操作這個對象時, 這個線程就獲得該對象的鎖,在此期間其他線程就無法操作該對象了

    Lock
    簡介:Lock是自JDK1.5 之后推出的一個接口,當(dāng)熱也是一系列子實現(xiàn)類,接口非常重要,定義了Java所認(rèn)定的鎖的概念,跟synchronized有顯著區(qū)別,
    synchronized是一個關(guān)鍵字,使用它可以實現(xiàn)類似鎖的效果,但是嚴(yán)格的來說它并不是鎖,Lock是一個接口,詳細(xì)描述了鎖的概念,其中重點包含若干方法,這些方法就是核心內(nèi)容了。
    方法:

    lock():這個方法用來加鎖,或者可以理解為獲取對象的鎖,如果獲取成功,就執(zhí)行下面的代碼,若獲取失敗則一直等待,重復(fù)嘗試獲取

    lockInterruptibly(); 也是嘗試獲取鎖,但是對應(yīng)帶了Interrupter這個部分,所以對于獲取鎖的結(jié)果會進行進一步工作;

    tryLock(); 嘗試獲取鎖,返回值boolean類型,會返回獲取鎖的結(jié)果,跟lock()不一樣,如果獲取失敗,返回false ,并且不會繼續(xù)嘗試獲取;

    unlock():解鎖,運行之后即可釋放鎖,就能讓其他線程獲取了;

    ReentrantLock:
    是最常用的子實現(xiàn)類,加強對它的熟悉字面翻譯它叫重入鎖,確實它也是符合重入鎖的要求,但是它僅僅可以表示重入鎖。

    可重入鎖:
    是一個概念,可重用鎖在大部分時候并不直接表示RenntrantLock,可重用鎖強調(diào)的是一種類型,這個類型關(guān)鍵特點是可重入,什么是可重入?
    就是一個已經(jīng)獲得鎖的線程還能繼續(xù)調(diào)用加鎖的代碼。
    這里我們強調(diào)可重入是一種典型的鎖的類型,我們自己可以編碼實現(xiàn)一些可重入鎖,在實際項目中它的運用可以體現(xiàn)靈活性等等諸多優(yōu)勢點,就不一一展開。

    ThreadDemo類

    /*** @Author: Jiangjun* @Date: 2019/10/7 11:53* @Description: 描述購票的邏輯*/ public class ThreadDemo implements Runnable{Lock lock = new ReentrantLock();volatile int num = 20;@Overridepublic void run() {lock.lock();while (num>0){addlock();System.out.println(Thread.currentThread().getName() + "認(rèn)為此時還有票可選");num = num - 1;System.out.println(Thread.currentThread().getName() + "買到了一張票,還剩" + num);}lock.unlock();}public void addlock(){lock.lock();}}

    主函數(shù):

    public class TestMain {public static void main(String[] args) {ThreadDemo td = new ThreadDemo();Thread t1 = new Thread(td,"掌上編程");Thread t2 = new Thread(td,"公眾號");t1.start();t2.start();} }

    公平鎖:

    公平=先來后到,先來的獲取鎖,就來的后獲取鎖。
    同樣公平鎖也是一種概念,也是一種鎖的類型,如果設(shè)計鎖的機制符合公平要求,那么這個鎖就是公平的鎖。

    若適用購票場景,如果強調(diào)先來后到,(從性能角度考慮)就必須采取特備的方案來實現(xiàn)這種先后順序,這樣必然會帶來性能損失,所以公平鎖的性能會劣于非公平鎖。

    如果我們使用非公平鎖也會帶帶來一定風(fēng)險,容易造成真實意義上的不公平,就有一些線程老早就在等待了,但是運氣不好一直拿不到鎖,這個可以成為鎖饑餓現(xiàn)象。

    因此我們強調(diào)根據(jù)情況來選擇鎖是否公平,一般如果要避免掉鎖饑餓現(xiàn)象,就要考慮使用公平鎖,否則可以使用非公平鎖。

    Synchronized 只能是非公平鎖
    ReentrantLock 是后來加入的類,所以在設(shè)計上更加完善,可以直接通過構(gòu)造函數(shù)來制定鎖是否公平。
    細(xì)節(jié)注意:

    養(yǎng)成比較規(guī)范的編碼習(xí)慣,一旦使了Lock,要充分考慮到可能出現(xiàn)的報錯情況,所以一般編碼會這樣寫try…catch…fianlly

    public class LockFairThread implements Runnable{//創(chuàng)建公平鎖private static ReentrantLock lock = new ReentrantLock(true);@Overridepublic void run() {lock.lock();try{System.out.println(Thread.currentThread().getName() + "獲得鎖");}catch (Exception e){System.out.println("異常相關(guān)提示");}finally {lock.unlock();}}}

    獨享鎖/共享鎖:

    獨享鎖只能提供一個線程所享用,共享鎖表示鎖可以提供多個線程享用。
    這里會覺得比較奇怪,感覺鎖好像就是提供一個線程使用,這個其實不絕對,比如一些操作是可以共享的,比如我們在修改數(shù)據(jù)時,必須要獨享,不允許多個地方同時對數(shù)據(jù)進行修改,容易導(dǎo)致一些錯誤,但是在讀取數(shù)據(jù)時,其實可以多線程一起讀。共享鎖主要在一些場合使用,提升一下靈活性。

    互斥鎖/讀寫鎖

    樂觀鎖/悲觀鎖:

    樂觀鎖強調(diào)認(rèn)為并發(fā)不一定會導(dǎo)致數(shù)據(jù)出現(xiàn)不一致等問題,所以原則來說就是允許并發(fā)的發(fā)生,比如允許多個線程同時讀寫同一個變量,但是單純的樂觀相信也是不行的,還要想辦法控制一下。
    所以樂觀鎖強調(diào)一種思路和理念通過方式來允許并發(fā)出現(xiàn)又能夠規(guī)避掉出錯的情況,典型的方案就是使用版本號控制,下面就詳細(xì)描述一下:

    場景是修改商品的庫存數(shù)據(jù),比如原本庫存100個,現(xiàn)在多個線程在操作商品表,他們在操作的時候,需要先讀取數(shù)據(jù),再減數(shù)據(jù),比如先要讀一下商品庫存還有多少個,如果足夠再做減法,減去商品的庫存。這個商品中如果使用悲觀鎖,就是非常簡單的直接把從讀商品到減商品做成同步的,同時同一時間只允許一個線程來做先讀后減。這就是悲觀鎖的典型思路,就是覺得一旦有并發(fā)出現(xiàn),多個線程同時讀寫數(shù)據(jù),一旦導(dǎo)致數(shù)據(jù)出現(xiàn)問題所以不允許出現(xiàn)并發(fā)情況的。顯然悲觀鎖使用得非常少。使用樂觀鎖,就是允許多個線程同時去讀寫商品庫存數(shù)據(jù),但是想要個法子讓他們同時讀寫之后還要不出問題。所以我們要加入一個檢查機制,如果發(fā)現(xiàn)出現(xiàn)問題的話,就取這次操作,重新來過.具體做法就是給商品表額外添加一個字段,叫做version,然后每次讀取商品之前先檢查詢version,再每一次修改商品之后讓version+1,d當(dāng)然操作和處理商品之前要檢查一下version是否匹配。
    下面我們通過一個現(xiàn)時場景進行描述:

    • 線程A查看庫存,此時讀取的版本號,發(fā)現(xiàn)是0.
    • 線程B查看庫存,此時讀取的版本號,發(fā)現(xiàn)是0.
    • 線程A此時想要修改庫存,所以檢查下庫存了,這時可以把檢查版本號和扣減庫存一次性完成,比如執(zhí)行如下sql:UPDATE 表明 SET 庫存=庫存-20,version=version+1 WHERE 商品id=…AND version=0
    • 執(zhí)行第三步之后,趕緊檢查一下自己修改是否成功,如果修改失敗,意味著什么?意味著此時在查詢數(shù)據(jù)時,根據(jù)版本號=0沒有查詢出來,表示在第一步和第三步之間,商品已經(jīng)被修改了,所以就要撤銷重做。如果修改成功,表示第一步和第三步之間沒有出現(xiàn)問題,商品庫存沒有被其他線程修改過,就可以順利的成功修改。
    • 讓B修改商品,此時就會失敗,因為線程A在過程中已經(jīng)修改過商品庫存了,之前N讀取的庫存已經(jīng)失效,它需要重新讀取。

    面試10個問題 1-2多線程

    • 多線程基礎(chǔ)(線程狀態(tài) 、run/start 、 Thread/Runnable)

    • 常用方法和經(jīng)典問題(wait notify join 生產(chǎn)消費者)

    • 同步基礎(chǔ) (volatile synchronized)

    • 核心類庫(Callable 集合)

    • JUC原子類(LongAdder AtomicReference)

    • JUC鎖 (Lock AQS RenntrantLock ReadWriteLock)

    • 鎖概念(重入鎖、公平鎖、讀寫鎖、樂觀鎖等等)

    總結(jié)

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

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