自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

字節(jié)面試:說說Java中的鎖機(jī)制?

開發(fā) 前端
Java 中的鎖(Locking)機(jī)制主要是為了解決多線程環(huán)境下,對(duì)共享資源并發(fā)訪問時(shí)的同步和互斥控制,以確保共享資源的安全訪問。

Java 中的鎖(Locking)機(jī)制主要是為了解決多線程環(huán)境下,對(duì)共享資源并發(fā)訪問時(shí)的同步和互斥控制,以確保共享資源的安全訪問。

鎖的作用主要體現(xiàn)在以下幾個(gè)方面:

  • 互斥訪問:確保在任何時(shí)刻,只有一個(gè)線程能夠訪問特定的資源或執(zhí)行特定的代碼段。這防止了多個(gè)線程同時(shí)修改同一資源導(dǎo)致的數(shù)據(jù)不一致問題。
  • 內(nèi)存可見性:通過鎖的獲取和釋放,可以確保在鎖保護(hù)的代碼塊中對(duì)共享變量的修改對(duì)其他線程可見。這是因?yàn)?Java 內(nèi)存模型(JMM)規(guī)定,對(duì)鎖的釋放會(huì)把修改過的共享變量從線程的工作內(nèi)存刷新到主內(nèi)存中,而獲取鎖時(shí)會(huì)從主內(nèi)存中讀取最新的共享變量值。
  • 保證原子性:鎖能夠保證在其保護(hù)的代碼塊內(nèi),一系列操作是不可分割的整體,即原子操作。這意味著在多線程環(huán)境下,這些操作不會(huì)被線程調(diào)度機(jī)制打斷,從而避免了數(shù)據(jù)的不完整修改。
  • 同步:協(xié)調(diào)線程間的執(zhí)行順序,使得某些操作在另一些操作完成之后再執(zhí)行,保證程序的邏輯正確性。例如,一個(gè)線程在寫入數(shù)據(jù)之后,另一個(gè)線程才能讀取該數(shù)據(jù),以確保讀取到的數(shù)據(jù)是最新的。

1.鎖策略

在 Java 中有很多鎖策略,用于對(duì)鎖進(jìn)行分類和指導(dǎo)鎖的(具體)實(shí)現(xiàn),這些鎖策略包括以下內(nèi)容:

  • 樂觀鎖:它基于一種樂觀的思想,即認(rèn)為數(shù)據(jù)一般情況下不會(huì)造成沖突,所以不會(huì)立即加上鎖,而是在數(shù)據(jù)進(jìn)行更新提交的時(shí)候再進(jìn)行檢查。如果發(fā)生沖突,則返回錯(cuò)誤信息,讓用戶決定如何去做。
  • 悲觀鎖:它總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)阻塞直到它拿到鎖。
  • 自旋鎖:如果持有鎖的線程能在很短時(shí)間內(nèi)釋放鎖,那么那些等待競(jìng)爭(zhēng)鎖的線程就不需要做內(nèi)核態(tài)和用戶態(tài)之間的切換進(jìn)入阻塞掛起狀態(tài),它們只需要等一等(自旋就是空循環(huán)),等持有鎖的線程釋放鎖后即可立即獲取鎖,這樣就避免用戶線程和內(nèi)核的切換的消耗。
  • 可重入鎖(遞歸鎖):指的是同一個(gè)線程外層函數(shù)獲得鎖之后,內(nèi)層遞歸函數(shù)仍然能獲得該鎖的代碼。即,線程可以進(jìn)入任何一個(gè)它已經(jīng)擁有的鎖所同步著的代碼塊。
  • 讀寫鎖:在讀寫場(chǎng)景中,讀操作可以并發(fā)進(jìn)行,但寫操作需要互斥進(jìn)行。通過讀寫鎖可以實(shí)現(xiàn)讀寫分離,提高系統(tǒng)的并發(fā)性能。
  • 公平鎖/非公平鎖:公平鎖是指多個(gè)線程按照申請(qǐng)鎖的順序來獲取鎖,類似排隊(duì)打飯,先到先得。非公平鎖是指多個(gè)線程獲取鎖的順序并不是按照申請(qǐng)鎖的順序,有可能后申請(qǐng)的線程比先申請(qǐng)的線程優(yōu)先獲取鎖。
  • 共享鎖/獨(dú)占鎖:共享鎖允許多個(gè)線程同時(shí)讀取一個(gè)資源,而獨(dú)占鎖則只允許一個(gè)線程訪問資源。
  • 輕量級(jí)鎖/重量級(jí)鎖:這些是 Java 在 JVM 層面對(duì) synchronized 鎖的優(yōu)化,以減少線程之間的競(jìng)爭(zhēng)和提高程序的性能。
  • 分段鎖:將一把鎖分成多段,允許不同的線程同時(shí)訪問不同的段,從而提高了并發(fā)訪問的性能。
  • 同步鎖:Java 內(nèi)建的一種同步機(jī)制,例如 synchronized,它可以修飾方法或代碼塊,用于保護(hù)共享資源的訪問。

2.鎖實(shí)現(xiàn)

在 Java 中也有一些具體的鎖實(shí)現(xiàn),用于代碼層面的鎖操作以此來保證線程安全的,這些常見的鎖實(shí)現(xiàn)有以下幾個(gè):

  • synchronized:內(nèi)置鎖(Monitor Lock),可以用于方法或代碼塊,提供互斥訪問。當(dāng)一個(gè)線程進(jìn)入 synchronized 方法或塊時(shí),它會(huì)自動(dòng)獲取對(duì)象的鎖,其他線程則需等待鎖釋放后才能進(jìn)入。
  • ReentrantLock:是一個(gè)重入鎖,是 java.util.concurrent.locks 包中的接口 Lock 的實(shí)現(xiàn),提供了比 synchronized 更靈活的鎖操作,如嘗試獲取鎖、可中斷的獲取鎖、超時(shí)獲取鎖等。它也支持公平鎖和非公平鎖策略。
  • ReentrantReadWriteLock(讀寫鎖):也是 java.util.concurrent.locks 包中的一部分,允許同時(shí)有多個(gè)讀取者,但只允許一個(gè)寫入者。它分為讀鎖和寫鎖,讀鎖之間不互斥,讀鎖與寫鎖互斥,寫鎖之間也互斥,適用于讀多寫少的場(chǎng)景。
  • StampedLock(Java 8 引入):提供了三種鎖模式:讀鎖、寫鎖和樂觀讀鎖。相較于 ReentrantReadWriteLock,StampedLock 提供了更細(xì)粒度的控制,支持樂觀讀取操作,可以提高并發(fā)性能。

(1)synchronized 使用

synchronized 可以用來修飾普通方法、靜態(tài)方法和代碼塊。

修飾普通方法

public synchronized void method() {
    // .......
}

當(dāng) synchronized 修飾普通方法時(shí),被修飾的方法被稱為同步方法,其作用范圍是整個(gè)方法,作用的對(duì)象是調(diào)用這個(gè)方法的對(duì)象。

修飾靜態(tài)方法

public static synchronized void staticMethod() {
    // .......
}

當(dāng) synchronized 修飾靜態(tài)的方法時(shí),其作用的范圍是整個(gè)方法,作用對(duì)象是調(diào)用這個(gè)類的所有對(duì)象。

修飾代碼塊

為了減少鎖的粒度,我們可以選擇在一個(gè)方法中的某個(gè)部分使用 synchronized 來修飾(一段代碼塊),從而實(shí)現(xiàn)對(duì)一個(gè)方法中的部分代碼進(jìn)行加鎖,實(shí)現(xiàn)代碼如下:

public void classMethod() throws InterruptedException {
    // 前置代碼...
    
    // 加鎖代碼
    synchronized (SynchronizedExample.class) {
        // ......
    }
    
    // 后置代碼...
}

以上代碼在執(zhí)行時(shí),被修飾的代碼塊稱為同步語(yǔ)句塊,其作用范圍是大括號(hào)“{}”括起來的代碼塊,作用的對(duì)象是調(diào)用這個(gè)代碼塊的對(duì)象。

(2)ReentrantLock 使用

ReentrantLock 基本使用:

// 1. 創(chuàng)建ReentrantLock對(duì)象
ReentrantLock lock = new ReentrantLock();
// 2.獲取鎖
lock.lock(); 
try {
    // 3.得到鎖,執(zhí)行需要同步的代碼塊
} finally {
    // 4.釋放鎖
    lock.unlock(); 
}

進(jìn)階使用:嘗試獲取鎖并設(shè)定超時(shí)時(shí)間(可選):

ReentrantLock lock = new ReentrantLock();
 // 嘗試獲取鎖,等待2秒,超時(shí)返回false
boolean locked = lock.tryLock(2, TimeUnit.SECONDS);
if (locked) {
    try {
        // 執(zhí)行需要同步的代碼塊
    } finally {
        lock.unlock();
    }
}

(3)ReentrantReadWriteLock 使用

ReentrantReadWriteLock 特點(diǎn)如下:

  • 多個(gè)線程可以同時(shí)獲取讀鎖,實(shí)現(xiàn)讀共享的并發(fā)訪問。
  • 寫鎖是排它的,一旦有一個(gè)線程獲取寫鎖,其他線程無法獲取讀鎖或?qū)戞i,直到寫鎖釋放。
  • 讀鎖與讀鎖之間可以共存,但寫鎖與讀鎖和寫鎖之間是互斥的。

也就是說:讀讀不互斥、讀寫互斥、寫寫互斥。

ReentrantReadWriteLock 基礎(chǔ)使用如下:

// 創(chuàng)建 ReentrantReadWriteLock 對(duì)象
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
// 創(chuàng)建讀鎖
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
// 獲取讀鎖
readLock.lock(); 
try {
    // 讀取共享資源的操作
} finally {
    // 釋放讀鎖
    readLock.unlock(); 
}
// 創(chuàng)建寫鎖
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
// 獲取寫鎖
writeLock.lock();
try {
    // 寫入共享資源的操作
} finally {
    // 釋放寫鎖
    writeLock.unlock(); 
}

(4)StampedLock 使用

StampedLock 有三種讀寫方法:

  • readLock():讀鎖,用于多線程并發(fā)讀取共享資源。
  • writeLock():寫鎖,用于獨(dú)占寫入共享資源。
  • tryOptimisticRead():讀樂觀鎖,用于在不阻塞其他線程的情況下嘗試讀取共享資源。

其中 readLock() 和 writeLock() 方法與 ReentrantReadWriteLock 的用法類似,而 tryOptimisticRead() 方法則是 StampedLock 引入的新方法,它用于非常短的讀操作,它是使用如下:

// 創(chuàng)建 StampedLock 實(shí)例
StampedLock lock = new StampedLock();
// 獲取樂觀讀鎖
long stamp = lock.tryOptimisticRead(); 
// 讀取共享變量
if (!lock.validate(stamp)) { // 檢查樂觀讀鎖是否有效
    stamp = lock.readLock(); // 如果樂觀讀鎖無效,則獲取悲觀讀鎖
    try {
        // 重新讀取共享變量
    } finally {
        lock.unlockRead(stamp); // 釋放悲觀讀鎖
    }
}

// 獲取悲觀讀鎖
long stamp = lock.readLock(); 
try {
    // 讀取共享變量
} finally {
    lock.unlockRead(stamp); // 釋放悲觀讀鎖
}

// 獲取寫鎖
long stamp = lock.writeLock(); 
try {
    // 寫入共享變量
} finally {
    lock.unlockWrite(stamp); // 釋放寫鎖
}

使用樂觀讀鎖的特性可以提高讀操作的并發(fā)性能,適用于讀多寫少的場(chǎng)景。如果樂觀讀鎖獲取后,在讀取共享變量前發(fā)生了寫入操作,則 validate 方法會(huì)返回 false,此時(shí)需要轉(zhuǎn)換為悲觀讀鎖或?qū)戞i重新訪問共享變量。

責(zé)任編輯:姜華 來源: Java中文社群
相關(guān)推薦

2021-06-29 09:47:34

ReactSetState機(jī)制

2020-12-14 11:35:22

SPI Java機(jī)制

2024-06-24 00:09:00

零拷貝技術(shù)MMapsendFile

2024-08-12 17:36:54

2021-06-30 07:19:36

React事件機(jī)制

2020-09-16 07:56:28

多線程讀寫鎖悲觀鎖

2022-08-17 08:17:01

SPI機(jī)制接口

2021-06-10 07:51:07

Node.js循環(huán)機(jī)制

2024-03-18 12:21:28

Java輕量級(jí)鎖重量級(jí)鎖

2019-05-10 10:50:04

Spring AOPJDK動(dòng)態(tài)代理CGLIB動(dòng)態(tài)代理

2020-07-19 10:26:47

Kubernetes數(shù)據(jù)結(jié)構(gòu)

2020-12-01 08:47:36

Java異常開發(fā)

2024-03-28 10:37:44

IoC依賴注入依賴查找

2019-10-17 08:51:00

Java悲觀鎖Monitor

2021-04-29 11:18:14

JVM加載機(jī)制

2020-04-24 15:44:50

MySQL數(shù)據(jù)庫(kù)鎖機(jī)制

2020-07-06 08:03:32

Java悲觀鎖樂觀鎖

2024-11-19 15:13:02

2023-12-27 18:16:39

MVCC隔離級(jí)別幻讀

2025-04-16 00:00:01

JWT客戶端存儲(chǔ)加密令
點(diǎn)贊
收藏

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