成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:說(shuō)說(shuō)讀寫(xiě)鎖實(shí)現(xiàn)原理?

開(kāi)發(fā) 前端
ReentrantReadWriteLock(讀寫(xiě)鎖)是 Java 并發(fā)包(java.util.concurrent.locks)中的一個(gè)類,它實(shí)現(xiàn)了一個(gè)可重入的讀寫(xiě)鎖。讀寫(xiě)鎖允許多個(gè)線程同時(shí)讀取共享資源,但在寫(xiě)入共享資源時(shí)只允許一個(gè)線程進(jìn)行。

在實(shí)際項(xiàng)目開(kāi)發(fā)中,并發(fā)編程一定會(huì)用(提升程序的執(zhí)行效率),而用到并發(fā)編程那么鎖機(jī)制就一定會(huì)用,因?yàn)殒i是保證并發(fā)編程的主要手段。

在 Java 中常用的鎖有以下幾個(gè):

  • synchronized(內(nèi)置鎖):Java 語(yǔ)言內(nèi)置的關(guān)鍵字,JVM 層級(jí)鎖實(shí)現(xiàn),使用起來(lái)較為簡(jiǎn)單直觀。
  • ReentrantLock(可重入鎖):需要顯式地獲取和釋放鎖,提供了更靈活的鎖操作方式。
  • ReentrantReadWriteLock(讀寫(xiě)鎖):性能較好,分為讀鎖和寫(xiě)鎖,允許多個(gè)讀線程同時(shí)獲取讀鎖,而寫(xiě)鎖具有排他性。
  • StampedLock(郵戳鎖):JDK 8 提供的鎖,提供了一種樂(lè)觀讀的方式,先嘗試讀取,如果在讀取過(guò)程中沒(méi)有發(fā)生寫(xiě)操作,則可以直接完成讀取,避免了獲取讀鎖的開(kāi)銷(xiāo)。

而我們今天重點(diǎn)要討論的是讀寫(xiě)鎖 ReentrantReadWriteLock 和它的實(shí)現(xiàn)原理。

1.讀寫(xiě)鎖介紹

ReentrantReadWriteLock(讀寫(xiě)鎖)是 Java 并發(fā)包(java.util.concurrent.locks)中的一個(gè)類,它實(shí)現(xiàn)了一個(gè)可重入的讀寫(xiě)鎖。讀寫(xiě)鎖允許多個(gè)線程同時(shí)讀取共享資源,但在寫(xiě)入共享資源時(shí)只允許一個(gè)線程進(jìn)行

它把鎖分為兩部分:讀鎖和寫(xiě)鎖,其中讀鎖允許多個(gè)線程同時(shí)獲得,因?yàn)樽x操作本身是線程安全的,而寫(xiě)鎖則是互斥鎖,不允許多個(gè)線程同時(shí)獲得寫(xiě)鎖,并且寫(xiě)操作和讀操作也是互斥的。

也就是說(shuō)讀寫(xiě)鎖的特征是:

  • 讀-讀操作不加鎖。
  • 讀-寫(xiě)操作加鎖。
  • 寫(xiě)-寫(xiě)操作加鎖。

2.基本使用

ReentrantReadWriteLock 鎖分為以下兩種:

  • ReentrantReadWriteLock.ReadLock 表示讀鎖:它提供了 lock 方法進(jìn)行加鎖、unlock 方法進(jìn)行解鎖。
  • ReentrantReadWriteLock.WriteLock 表示寫(xiě)鎖:它提供了 lock 方法進(jìn)行加鎖、unlock 方法進(jìn)行解鎖。

它的基礎(chǔ)使用如下代碼所示:

// 創(chuàng)建讀寫(xiě)鎖
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 獲得讀鎖
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 獲得寫(xiě)鎖
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 讀鎖使用
readLock.lock();
try {
    // 業(yè)務(wù)代碼...
} finally {
    readLock.unlock();
}
// 寫(xiě)鎖使用
writeLock.lock();
try {
    // 業(yè)務(wù)代碼...
} finally {
    writeLock.unlock();
}

(1)讀讀不互斥

多個(gè)線程可以同時(shí)獲取到讀鎖,稱之為讀讀不互斥,如下代碼所示:

// 創(chuàng)建讀寫(xiě)鎖
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 創(chuàng)建讀鎖
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
Thread t1 = new Thread(() -> {
    readLock.lock();
    try {
        System.out.println("[t1]得到讀鎖.");
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        System.out.println("[t1]釋放讀鎖.");
        readLock.unlock();
    }
});
t1.start();
Thread t2 = new Thread(() -> {
    readLock.lock();
    try {
        System.out.println("[t2]得到讀鎖.");
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        System.out.println("[t2]釋放讀鎖.");
        readLock.unlock();
    }
});
t2.start();

以上程序執(zhí)行結(jié)果如下:

(2)讀寫(xiě)互斥

讀鎖和寫(xiě)鎖同時(shí)使用是互斥的(也就是不能同時(shí)獲得),這稱之為讀寫(xiě)互斥,如下代碼所示:

// 創(chuàng)建讀寫(xiě)鎖
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 創(chuàng)建讀鎖
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 創(chuàng)建寫(xiě)鎖
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 使用讀鎖
Thread t1 = new Thread(() -> {
    readLock.lock();
    try {
        System.out.println("[t1]得到讀鎖.");
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        System.out.println("[t1]釋放讀鎖.");
        readLock.unlock();
    }
});
t1.start();
// 使用寫(xiě)鎖
Thread t2 = new Thread(() -> {
    writeLock.lock();
    try {
        System.out.println("[t2]得到寫(xiě)鎖.");
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        System.out.println("[t2]釋放寫(xiě)鎖.");
        writeLock.unlock();
    }
});
t2.start();

以上程序執(zhí)行結(jié)果如下:

(3)寫(xiě)寫(xiě)互斥

多個(gè)線程同時(shí)使用寫(xiě)鎖也是互斥的,這稱之為寫(xiě)寫(xiě)互斥,如下代碼所示:

// 創(chuàng)建讀寫(xiě)鎖
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 創(chuàng)建寫(xiě)鎖
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
Thread t1 = new Thread(() -> {
    writeLock.lock();
    try {
        System.out.println("[t1]得到寫(xiě)鎖.");
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        System.out.println("[t1]釋放寫(xiě)鎖.");
        writeLock.unlock();
    }
});
t1.start();

Thread t2 = new Thread(() -> {
    writeLock.lock();
    try {
        System.out.println("[t2]得到寫(xiě)鎖.");
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        System.out.println("[t2]釋放寫(xiě)鎖.");
        writeLock.unlock();
    }
});
t2.start();

以上程序執(zhí)行結(jié)果如下:

(4)優(yōu)點(diǎn)分析

  1. 提高了程序執(zhí)行性能:多個(gè)讀鎖可以同時(shí)執(zhí)行,相比于普通鎖在任何情況下都要排隊(duì)執(zhí)行來(lái)說(shuō),讀寫(xiě)鎖提高了程序的執(zhí)行性能。
  2. 避免讀到臨時(shí)數(shù)據(jù):讀鎖和寫(xiě)鎖是互斥排隊(duì)執(zhí)行的,這樣可以保證了讀取操作不會(huì)讀到寫(xiě)了一半的臨時(shí)數(shù)據(jù)。

(5)適用場(chǎng)景

讀寫(xiě)鎖適合多讀少寫(xiě)的業(yè)務(wù)場(chǎng)景,此時(shí)讀寫(xiě)鎖的優(yōu)勢(shì)最大。

3.底層實(shí)現(xiàn)

ReentrantReadWriteLock 是基于 AbstractQueuedSynchronizer(AQS)實(shí)現(xiàn)的,AQS 以單個(gè) int 類型的原子變量來(lái)表示其狀態(tài),并通過(guò) CAS 操作來(lái)保證線程安全。

這點(diǎn)也通過(guò) ReentrantReadWriteLock 源碼發(fā)現(xiàn),ReentrantReadWriteLock 中的公平鎖繼承了 AbstractQueuedSynchronizer(AQS):

而 ReentrantReadWriteLock 中的非公平鎖繼承了公平鎖(公平鎖繼承了 AbstractQueuedSynchronizer):

所以可以看出 ReentrantReadWriteLock 其底層主要是通過(guò) AQS 實(shí)現(xiàn)的。

4.AQS

AbstractQueuedSynchronizer(AQS)是 Java 并發(fā)包中的一個(gè)抽象類,位于 java.util.concurrent.locks 包中。它為實(shí)現(xiàn)依賴于“獨(dú)占”和“共享”模式的阻塞鎖和相關(guān)同步器提供了一個(gè)框架。

AQS 是許多高級(jí)同步工具的基礎(chǔ),例如 ReentrantLock、ReentrantReadWriteLock、CountDownLatch 和 Semaphore。

(1)AQS 核心概念

AQS 中有兩個(gè)最主要的內(nèi)容:

  • 同步狀態(tài)(State):用于表示同步器的狀態(tài),例如鎖的持有數(shù)量、資源的可用數(shù)量等。可以通過(guò) getState()、setState() 和 compareAndSetState() 方法來(lái)操作。
  • 等待隊(duì)列(CLH 隊(duì)列):由雙向鏈表實(shí)現(xiàn)的等待線程隊(duì)列。當(dāng)線程獲取同步狀態(tài)失敗時(shí),會(huì)被封裝成節(jié)點(diǎn)加入到等待隊(duì)列中。

(2)AQS 工作流程

AQS 工作流程主要分為以下兩部分。

加鎖與釋放鎖:

  • 線程嘗試獲取同步狀態(tài),如果獲取成功,則直接執(zhí)行后續(xù)操作。
  • 如果獲取失敗,則將當(dāng)前線程封裝成節(jié)點(diǎn)加入等待隊(duì)列,并阻塞當(dāng)前線程。
  • 當(dāng)持有鎖的線程釋放鎖時(shí),會(huì)喚醒等待隊(duì)列中的后繼節(jié)點(diǎn)線程,使其重新嘗試獲取鎖。

等待與喚醒:

  • 等待隊(duì)列中的節(jié)點(diǎn)通過(guò)自旋和阻塞來(lái)等待被喚醒。
  • 喚醒操作會(huì)按照一定的規(guī)則選擇等待隊(duì)列中的節(jié)點(diǎn)進(jìn)行喚醒。
責(zé)任編輯:姜華 來(lái)源: 磊哥和Java
相關(guān)推薦

2024-03-05 10:33:39

AOPSpring編程

2024-08-22 10:39:50

@Async注解代理

2024-02-29 16:49:20

volatileJava并發(fā)編程

2024-08-29 16:30:27

2024-03-28 10:37:44

IoC依賴注入依賴查找

2024-03-14 14:56:22

反射Java數(shù)據(jù)庫(kù)連接

2024-12-06 07:00:00

2024-07-31 08:28:37

DMAIOMMap

2021-05-20 08:34:03

CDN原理網(wǎng)絡(luò)

2024-03-22 06:56:24

零拷貝技術(shù)數(shù)據(jù)傳輸數(shù)據(jù)拷貝

2024-09-20 08:36:43

零拷貝數(shù)據(jù)傳輸DMA

2024-11-15 15:27:09

2025-02-28 00:00:00

2024-06-04 09:02:03

2021-06-07 17:12:22

線程安全Atomic

2025-04-07 00:00:00

MySQL數(shù)據(jù)庫(kù)服務(wù)器

2024-03-01 11:33:31

2024-12-04 14:45:14

零拷貝技術(shù)CPU 拷貝Zero-copy

2023-12-27 18:16:39

MVCC隔離級(jí)別幻讀

2024-11-19 15:13:02

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美一级小视频 | 精品一区二区视频 | 国产精品久久久久aaaa九色 | 欧美综合一区 | 国产精品永久久久久 | 久久中文字幕一区 | 国产激情在线 | 天堂一区 | 日韩a视频| 黄色大全免费看 | 日韩一区二区在线观看视频 | 免费啪啪 | 青草青草久热精品视频在线观看 | 日本精品视频在线 | 国产一区二区三区免费 | 成年人在线电影 | 久久久久久久久99 | 国产精品欧美一区二区三区不卡 | 久久久国产一区二区三区四区小说 | 日本三级电影在线免费观看 | 久久久久精 | 免费观看a级毛片在线播放 黄网站免费入口 | 视频一区在线 | 欧美激情区 | 日韩爱爱网 | 久久国产精品久久久久 | 久久久久久久久久影视 | 天天综合网永久 | 国产亚洲成av人在线观看导航 | 亚洲精品成人av久久 | 香蕉视频久久久 | 中文字幕乱码一区二区三区 | 欧美日韩一区二区三区视频 | av在线一区二区三区 | 在线观看亚 | 一区二区三区小视频 | 欧美bondage紧缚视频 | 91精品国产91久久久久久吃药 | 精品国产一级 | 国产精品国产 | 欧美精品成人一区二区三区四区 |