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

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java中的锁的概念大汇总

發(fā)布時(shí)間:2025/3/19 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中的锁的概念大汇总 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 公平鎖/非公平鎖
      • 公平鎖
      • 非公平鎖
    • 樂(lè)觀鎖/悲觀鎖
      • 樂(lè)觀鎖
      • 悲觀鎖
    • 獨(dú)占鎖/共享鎖
      • 獨(dú)占鎖(排它鎖)
      • 共享鎖
    • 互斥鎖/讀寫(xiě)鎖
      • 互斥鎖
      • 讀寫(xiě)鎖
    • 偏向鎖/輕量級(jí)鎖/重量級(jí)鎖
      • 偏向鎖
      • 輕量級(jí)鎖
      • 重量級(jí)鎖
    • 可重入鎖
    • 分段鎖
    • 自旋鎖
    • 鎖粗化
    • 鎖消除

公平鎖/非公平鎖

公平鎖

公平鎖指的是多線(xiàn)程環(huán)境中按照申請(qǐng)鎖的順序獲取鎖,類(lèi)似FIFO隊(duì)列,先申請(qǐng)鎖的線(xiàn)程在有資源的情況下保證先獲取到鎖。
示例說(shuō)明一下公平鎖:

public class FairLockDemo {//內(nèi)部類(lèi)公平鎖測(cè)試static class FairLockRunnable implements Runnable {ReentrantLock reentrantLock = new ReentrantLock(false);//設(shè)置false代表是公平鎖,默認(rèn)是非公平鎖@Overridepublic void run() {String threadName = Thread.currentThread().getName();//獲取線(xiàn)程名稱(chēng)reentrantLock.lock();//獲取鎖try {System.out.println("[" + threadName + "] 獲取鎖");Thread.sleep(2000);//模擬執(zhí)行任務(wù),睡2s} catch (Exception e) {e.printStackTrace();} finally {reentrantLock.unlock();//釋放鎖System.out.println("[" + threadName + "] 釋放鎖");}}}public static void main(String[] args) {ExecutorService executor = Executors.newCachedThreadPool();//定義依噶線(xiàn)程池for (int i = 0; i < 5; i++) {executor.execute(new FairLockRunnable());}executor.shutdown();//線(xiàn)程池優(yōu)雅關(guān)閉} }

打印結(jié)果:

[pool-1-thread-2] 獲取鎖 [pool-1-thread-1] 獲取鎖 [pool-1-thread-4] 獲取鎖 [pool-1-thread-3] 獲取鎖 [pool-1-thread-5] 獲取鎖 [pool-1-thread-2] 釋放鎖 [pool-1-thread-1] 釋放鎖 [pool-1-thread-4] 釋放鎖 [pool-1-thread-3] 釋放鎖 [pool-1-thread-5] 釋放鎖

可以看出來(lái)這里獲取鎖和釋放鎖的順序是按照申請(qǐng)鎖的順序來(lái)的,這就是公平鎖。 new ReentrantLock(false)是一種公平鎖。

非公平鎖

非公平鎖對(duì)應(yīng)的是公平鎖,在多線(xiàn)程環(huán)境中獲取鎖的順序并不是按申請(qǐng)鎖的順序來(lái)進(jìn)行的。
測(cè)試代碼跟上面的一樣,只需要改一處地方:

ReentrantLock reentrantLock = new ReentrantLock();//設(shè)置false代表是公平鎖,默認(rèn)是非公平鎖

打印結(jié)果:

[pool-1-thread-1] 獲取鎖 [pool-1-thread-2] 獲取鎖 [pool-1-thread-3] 獲取鎖 [pool-1-thread-4] 獲取鎖 [pool-1-thread-5] 獲取鎖 [pool-1-thread-2] 釋放鎖 [pool-1-thread-3] 釋放鎖 [pool-1-thread-4] 釋放鎖 [pool-1-thread-1] 釋放鎖 [pool-1-thread-5] 釋放鎖

可以看出,獲取鎖的順序并沒(méi)有按照申請(qǐng)鎖的順序來(lái)走,其實(shí)是隨機(jī)的。非公平鎖可以增加業(yè)務(wù)的吞吐量,因?yàn)槭请S機(jī)讓獲取到資源的線(xiàn)程執(zhí)行的,但是有可能造成優(yōu)先級(jí)反轉(zhuǎn)或者線(xiàn)程饑餓問(wèn)題(可能存在有個(gè)倒霉的線(xiàn)程一直獲取不到鎖,一直在等待),因此是不公平的鎖。

樂(lè)觀鎖/悲觀鎖

樂(lè)觀鎖和悲觀鎖更像是某種思想,就像是看待問(wèn)題的方式,樂(lè)觀鎖傾向于樂(lè)觀的方式看待數(shù)據(jù)認(rèn)為每次獲取的只有一個(gè)線(xiàn)程,悲觀鎖傾向于悲觀的方式看待數(shù)據(jù)認(rèn)為每次獲取都是多個(gè)線(xiàn)程,所以需要將數(shù)據(jù)鎖定只讓一個(gè)線(xiàn)程訪(fǎng)問(wèn)。

樂(lè)觀鎖

樂(lè)觀鎖總是認(rèn)為不存在多線(xiàn)程并發(fā)問(wèn)題,因此每次獲取數(shù)據(jù)的時(shí)候總認(rèn)為不會(huì)有其他線(xiàn)程對(duì)數(shù)據(jù)進(jìn)行修改,因此不會(huì)上鎖。但是更新的時(shí)候會(huì)進(jìn)行數(shù)據(jù)的比較以防止被其他線(xiàn)程已經(jīng)修改。實(shí)現(xiàn)方式一般使用“數(shù)據(jù)版本機(jī)制”或者“CAS操作”來(lái)實(shí)現(xiàn)。

  • 數(shù)據(jù)版本機(jī)制就是在在數(shù)據(jù)庫(kù)表字段加一個(gè)version字段。這個(gè)字段代表被修改的次數(shù),每當(dāng)數(shù)據(jù)被修改version就加1。 修改的時(shí)候一定要等得到查詢(xún)的version和數(shù)據(jù)庫(kù)中存在的version相等在更新,否則更新失敗。
  • CAS(Compare and Swap)比較并交換。CAS包含三個(gè)操作數(shù): 內(nèi)存為值(V)、進(jìn)行比較的預(yù)期原值(A)、擬修改的新值(B)。如果內(nèi)存位置V的值和預(yù)期原值A(chǔ)相匹配,那么比較器會(huì)將新值更新為B,否則不做處理。
  • 在Java中java.util.concurrent.atomic包下面的原子變量類(lèi)就是使用了樂(lè)觀鎖的一種實(shí)現(xiàn)方式CAS(Compare and Swap 比較并交換)實(shí)現(xiàn)的。

    悲觀鎖

    悲觀鎖總是認(rèn)為數(shù)據(jù)總是多線(xiàn)程訪(fǎng)問(wèn)的,如果對(duì)數(shù)據(jù)進(jìn)行操作必須加鎖實(shí)現(xiàn)。對(duì)數(shù)據(jù)操作之前加鎖,操作完成或者操作異常都要解鎖。
    悲觀鎖有synchronized、ReentrantLock等。

    獨(dú)占鎖/共享鎖

    獨(dú)占鎖(排它鎖)

    獨(dú)占鎖指的是鎖資源被一個(gè)線(xiàn)程所持有,每一次只能一個(gè)線(xiàn)程獨(dú)占使用。ReentrantLock和 synchronized都是獨(dú)占鎖。

    共享鎖

    共享鎖指的是鎖資源可以被多個(gè)線(xiàn)程持有的。如果線(xiàn)程A對(duì)數(shù)據(jù)Data加共享鎖后,其他線(xiàn)程只能對(duì)Data再加共享鎖,不能加獨(dú)占鎖。獨(dú)占鎖和共享鎖在JAVA中都是通過(guò)AQS實(shí)現(xiàn)的。 ReentrantReadWriteLock讀鎖是共享鎖,寫(xiě)鎖是獨(dú)占鎖。讀鎖的共享可以保證并發(fā)讀是高效的,讀寫(xiě),寫(xiě)讀,寫(xiě)寫(xiě)是互斥的。

    互斥鎖/讀寫(xiě)鎖

    互斥鎖

    互斥鎖指的最多只能有一個(gè)線(xiàn)程持有的鎖,屬于獨(dú)占鎖的一種。ReentrantLock和 synchronized都是互斥鎖。

    讀寫(xiě)鎖

    讀寫(xiě)鎖指的具體的關(guān)于讀寫(xiě)的一種鎖,既有獨(dú)占鎖又有共享鎖,read模式就是共享的,但是write模式是獨(dú)占的。
    讀寫(xiě)鎖的機(jī)制:

  • “讀-讀”不互斥
  • “讀-寫(xiě)”互斥
  • “寫(xiě)-寫(xiě)”互斥
  • java中讀寫(xiě)鎖的實(shí)現(xiàn)是ReentrantReadWriteLock。

    偏向鎖/輕量級(jí)鎖/重量級(jí)鎖

    這三種鎖是指鎖的狀態(tài),并且是針對(duì)Synchronized。在Java 5通過(guò)引入鎖升級(jí)的機(jī)制來(lái)實(shí)現(xiàn)高效Synchronized。這三種鎖的狀態(tài)是通過(guò)對(duì)象監(jiān)視器在對(duì)象頭中的字段來(lái)表明的。
    JVM通過(guò)以下方式關(guān)閉偏向鎖:

    -XX:-UseBiasedLocking

    偏向鎖

    偏向鎖是指一段同步代碼一直被一個(gè)線(xiàn)程所訪(fǎng)問(wèn),那么該線(xiàn)程會(huì)自動(dòng)獲取鎖。降低獲取鎖的代價(jià)。

    輕量級(jí)鎖

    輕量級(jí)鎖是指當(dāng)鎖是偏向鎖的時(shí)候,被另一個(gè)線(xiàn)程所訪(fǎng)問(wèn),偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,其他線(xiàn)程會(huì)通過(guò)自旋的形式嘗試獲取鎖,不會(huì)阻塞,提高性能。

    重量級(jí)鎖

    重量級(jí)鎖是指當(dāng)鎖為輕量級(jí)鎖的時(shí)候,另一個(gè)線(xiàn)程雖然是自旋,但自旋不會(huì)一直持續(xù)下去,當(dāng)自旋一定次數(shù)的時(shí)候,還沒(méi)有獲取到鎖,就會(huì)進(jìn)入阻塞,該鎖膨脹為重量級(jí)鎖。重量級(jí)鎖會(huì)讓他申請(qǐng)的線(xiàn)程進(jìn)入阻塞,性能降低。

    可重入鎖

    可重入的意思其實(shí)就是可重復(fù)使用,就是一把鎖可以重復(fù)多次用,但是注意需要按照獲取鎖的次數(shù)進(jìn)行解鎖,也就是加鎖此時(shí)一定要等于解鎖次數(shù)。ReentrantLock和 synchronized都是可重入鎖。

    分段鎖

    分段鎖指的是一種設(shè)計(jì),并非真正的鎖。對(duì)于ConcurrentHashMap而言,其并發(fā)的實(shí)現(xiàn)就是通過(guò)分段鎖的形式來(lái)實(shí)現(xiàn)高效的并發(fā)操作。分段鎖的設(shè)計(jì)目的是細(xì)化鎖的粒度,當(dāng)操作不需要更新整個(gè)數(shù)組的時(shí)候,就僅僅針對(duì)數(shù)組中的一項(xiàng)進(jìn)行加鎖操作。

    自旋鎖

    自旋鎖其實(shí)也不是真正的鎖,只是一種現(xiàn)象的描述,原理就是通過(guò)循環(huán)去實(shí)現(xiàn)。
    例如JDK源碼中很多都是通過(guò)for循環(huán)實(shí)現(xiàn)自旋鎖的。

    for (;;) {省略業(yè)務(wù)代碼......}

    鎖粗化

    鎖粗化簡(jiǎn)單理解就是將多個(gè)鎖合并成一個(gè),減少重復(fù)鎖請(qǐng)求帶來(lái)的性能損耗。一個(gè)例子理解:

    public void doSomethingMethod(){while(i<1000){synchronized(lock){//do some thing}} }

    鎖粗化之后的代碼

    public void doSomethingMethod(){synchronized(lock){while(i<1000){//do some thing}} }

    鎖消除

    鎖消除是發(fā)生在編譯器級(jí)別的一種鎖優(yōu)化方式。舉個(gè)簡(jiǎn)單例子可以理解:

    public synchronized void logApend(String content){StringBuffer sb = new StringBuffer();sb.append(content);}

    代碼非常簡(jiǎn)單,就是向StringBuffer中添加內(nèi)容的方法,并且這個(gè)方法是synchronized來(lái)修飾的。其實(shí)我們看apppd方法的源碼發(fā)現(xiàn)這里也有一個(gè)synchronized來(lái)修飾。

    @Overridepublic synchronized StringBuffer append(String str) {toStringCache = null;super.append(str);return this;}

    我們可以通過(guò)編譯器將其優(yōu)化,將鎖消除。
    前提是java必須運(yùn)行在server模式(server模式會(huì)比client模式作更多的優(yōu)化),同時(shí)必須開(kāi)啟逃逸分析:

    -server -XX:+DoEscapeAnalysis -XX:+EliminateLocks

    +DoEscapeAnalysis:開(kāi)啟逃逸分析
    +EliminateLocks:鎖消除。

    總結(jié)

    以上是生活随笔為你收集整理的Java中的锁的概念大汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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