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

Java的樂觀鎖,悲觀鎖,讀寫鎖,遞歸鎖

開發(fā) 前端
ReentrantReadWriteLock還有一個(gè)構(gòu)造方法,它接受一個(gè)布爾值參數(shù)fair,用于指定鎖是否應(yīng)該是公平的。如果設(shè)置為true,則等待時(shí)間最長(zhǎng)的線程將優(yōu)先獲得鎖。但是,公平鎖可能會(huì)降低性能,因?yàn)樾枰S護(hù)一個(gè)有序的等待隊(duì)列。

我們都知道在 Java 中為了保證一些操作的安全性,就會(huì)涉及到使用鎖,但是你對(duì) Java 的鎖了解的有多少呢?Java 都有哪些鎖?以及他們是怎么實(shí)現(xiàn)的,今天了不起就來說說關(guān)于 Java 的鎖。

樂觀鎖

樂觀鎖(Optimistic Locking)是一種在數(shù)據(jù)讀取時(shí)不會(huì)阻塞其他讀取或?qū)懭氩僮鞯逆i策略,但在更新時(shí)會(huì)檢查在此期間是否有其他操作修改了數(shù)據(jù)。如果數(shù)據(jù)已被修改,則更新操作會(huì)失敗,通常是通過重試或拋出異常來處理。

在 Java 中,樂觀鎖通常是通過版本號(hào)、時(shí)間戳或其他狀態(tài)信息來實(shí)現(xiàn)的。以下是樂觀鎖在 Java 中的一些常見實(shí)現(xiàn)方式:

版本號(hào)機(jī)制:

  • 數(shù)據(jù)表中增加一個(gè)“版本號(hào)”字段。
  • 讀取數(shù)據(jù)時(shí),同時(shí)讀取版本號(hào)。
  • 更新數(shù)據(jù)時(shí),將版本號(hào)加1,并帶上WHERE子句,確保版本號(hào)與讀取時(shí)的一致。
  • 如果更新影響的行數(shù)為0,則表示在此期間數(shù)據(jù)已被其他事務(wù)修改。

時(shí)間戳機(jī)制:

  • 類似于版本號(hào),但使用時(shí)間戳字段代替。
  • 更新時(shí)檢查時(shí)間戳字段,確保它與讀取時(shí)的時(shí)間戳匹配。

CAS (Compare-and-Swap) 操作:

  • 是一種原子操作,用于在多線程環(huán)境中安全地更新共享變量。
  • CAS操作包括三個(gè)參數(shù):內(nèi)存位置(V)、預(yù)期原值(A)和新值(B)。
  • 如果內(nèi)存位置V的值與預(yù)期原值A(chǔ)匹配,則將V的值更新為新值B。否則,不執(zhí)行任何操作。
  • Java 的 AtomicInteger、AtomicLong 等原子類就使用了CAS操作。

JPA 和 Hibernate 的樂觀鎖:

  • JPA 和 Hibernate 提供了內(nèi)置的樂觀鎖支持。
  • 在實(shí)體類中添加一個(gè)版本號(hào)或時(shí)間戳字段,并使用 @Version 注解標(biāo)記。
  • 當(dāng) Hibernate 或 JPA 嘗試更新一個(gè)實(shí)體時(shí),它會(huì)自動(dòng)檢查版本號(hào)或時(shí)間戳字段,以確保數(shù)據(jù)在此期間沒有被其他事務(wù)修改。

悲觀鎖

悲觀鎖(Pessimistic Locking)是一種在數(shù)據(jù)處理過程中,總是假設(shè)最壞的情況來避免數(shù)據(jù)并發(fā)問題的鎖策略。在Java中,悲觀鎖通常在數(shù)據(jù)被訪問時(shí)就立即加鎖,以保證在此期間其他任何事務(wù)都不能修改這個(gè)數(shù)據(jù),直到該事務(wù)完成為止。

Java中實(shí)現(xiàn)悲觀鎖的常見方式有以下幾種:

數(shù)據(jù)庫(kù)行級(jí)鎖和表級(jí)鎖:

  • 行級(jí)鎖:對(duì)正在訪問的數(shù)據(jù)行加鎖,防止其他事務(wù)修改該行。這是數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)提供的一種鎖機(jī)制,可以通過SQL語(yǔ)句來實(shí)現(xiàn)。
  • 表級(jí)鎖:對(duì)整個(gè)表加鎖,限制其他事務(wù)對(duì)該表的并發(fā)訪問。這種鎖的開銷較小,但并發(fā)性能較低。

Java中的synchronized關(guān)鍵字:

  • synchronized是Java語(yǔ)言內(nèi)建的線程同步機(jī)制,它可以用來修飾方法或者以代碼塊的形式出現(xiàn)。當(dāng)一個(gè)線程進(jìn)入一個(gè)synchronized修飾的方法或代碼塊時(shí),它會(huì)獲取一個(gè)鎖,其他嘗試進(jìn)入該區(qū)域的線程將會(huì)被阻塞,直到第一個(gè)線程釋放鎖。

ReentrantLock類:

  • Java的java.util.concurrent.locks.ReentrantLock類提供了重入鎖的實(shí)現(xiàn),這是一種悲觀鎖。與synchronized相比,ReentrantLock提供了更高的靈活性,比如可以嘗試獲取鎖、定時(shí)獲取鎖以及中斷等待鎖的線程等。

讀寫鎖(ReadWriteLock):

  • java.util.concurrent.locks.ReadWriteLock接口定義了讀取和寫入鎖的規(guī)則。雖然它本身不是悲觀鎖,但其中的寫鎖部分是一種悲觀鎖策略。寫鎖會(huì)阻止其他線程進(jìn)行讀和寫操作,直到持有鎖的線程釋放它。

分布式鎖:

  • 在分布式系統(tǒng)中,悲觀鎖的概念可以擴(kuò)展到跨多個(gè)進(jìn)程或機(jī)器。常見的實(shí)現(xiàn)方式包括使用Redis、Zookeeper等分布式協(xié)調(diào)服務(wù)來實(shí)現(xiàn)分布式鎖。

在使用悲觀鎖時(shí),需要注意死鎖和性能問題。死鎖是指兩個(gè)或多個(gè)線程無限期地等待對(duì)方釋放資源的情況。性能問題則可能由于鎖的粒度過大(如表級(jí)鎖)導(dǎo)致并發(fā)性能下降。

樂觀鎖與悲觀鎖的比較:

悲觀鎖:假設(shè)最壞的情況,每次訪問數(shù)據(jù)時(shí)都會(huì)鎖定數(shù)據(jù),防止其他事務(wù)修改。

樂觀鎖:假設(shè)最好的情況,允許其他事務(wù)并發(fā)訪問數(shù)據(jù),但在更新時(shí)會(huì)檢查數(shù)據(jù)是否被修改。

選擇哪種鎖策略取決于應(yīng)用的具體需求和并發(fā)場(chǎng)景。使用樂觀鎖時(shí),需要注意處理更新失敗的情況,通常是通過重試、拋出異?;蚪o用戶反饋來實(shí)現(xiàn)的。

遞歸鎖

Java中的遞歸鎖(ReentrantLock)是java.util.concurrent.locks包下提供的一種可重入的互斥鎖,它是悲觀鎖的一種實(shí)現(xiàn)。遞歸鎖允許一個(gè)線程多次獲取同一個(gè)鎖,而不會(huì)造成死鎖,這對(duì)于某些需要遞歸調(diào)用或者在一個(gè)線程中多次需要獲取同一個(gè)鎖的場(chǎng)景非常有用。

遞歸鎖的幾個(gè)特性:

可重入性:如果一個(gè)線程已經(jīng)擁有了一個(gè)遞歸鎖,那么它可以再次獲取該鎖而不會(huì)阻塞。每次獲取鎖,都會(huì)增加鎖的持有計(jì)數(shù);每次釋放鎖,都會(huì)減少持有計(jì)數(shù)。只有當(dāng)持有計(jì)數(shù)減少到0時(shí),其他線程才能獲取該鎖。

公平性:遞歸鎖可以是公平的也可以是非公平的。公平性意味著鎖的獲取是按照線程請(qǐng)求鎖的順序來的,而非公平性則不保證順序。公平的遞歸鎖可以減少“線程饑餓”的問題,但可能會(huì)降低性能。

既然我們說她是一個(gè)悲觀鎖的實(shí)現(xiàn),那么是不是可以和 synchronized 比較一下,有什么不同呢?

與Java內(nèi)置的synchronized關(guān)鍵字相比,遞歸鎖提供了更高的靈活性和更好的性能控制。例如,遞歸鎖支持嘗試獲取鎖(tryLock()方法)、定時(shí)獲取鎖(tryLock(long timeout, TimeUnit unit)方法)以及中斷等待鎖的線程(lockInterruptibly()方法)。

我們看一下遞歸鎖的示例代碼:

import java.util.concurrent.locks.ReentrantLock;  

public class RecursiveLockExample {  
    private final ReentrantLock lock = new ReentrantLock();  

    public void someMethod() {  
        lock.lock();  
        try {  
            // 臨界區(qū)代碼  
            // ...  
            someNestedMethod();  
            // ...  
        } finally {  
            lock.unlock();  
        }  
    }  

    private void someNestedMethod() {  
        lock.lock();  
        try {  
            // 嵌套調(diào)用中需要同步的代碼  
            // ...  
        } finally {  
            lock.unlock();  
        }  
    }  
}

在上面的示例中,someMethod方法調(diào)用了someNestedMethod方法,并且兩者都需要獲取同一個(gè)遞歸鎖。由于ReentrantLock是可重入的,所以這種調(diào)用不會(huì)造成死鎖。

讀寫鎖

Java中的讀寫鎖(ReadWriteLock)是一種允許多個(gè)讀線程和單個(gè)寫線程訪問共享資源的同步機(jī)制。ReadWriteLock接口在java.util.concurrent.locks包中定義,它包含兩個(gè)鎖:一個(gè)讀鎖和一個(gè)寫鎖。

讀寫鎖的特性:

讀共享:在沒有線程持有寫鎖時(shí),多個(gè)線程可以同時(shí)持有讀鎖來讀取共享資源。這可以提高并發(fā)性能,因?yàn)樽x操作通常不會(huì)修改數(shù)據(jù),所以允許多個(gè)讀線程并發(fā)訪問是安全的。

寫?yīng)氄迹寒?dāng)一個(gè)線程持有寫鎖時(shí),其他線程既不能獲取讀鎖也不能獲取寫鎖。這是為了確保寫操作對(duì)共享資源的獨(dú)占訪問,從而防止數(shù)據(jù)不一致。

Java中ReadWriteLock接口的主要實(shí)現(xiàn)類是ReentrantReadWriteLock,它提供了可重入的讀寫鎖實(shí)現(xiàn)。ReentrantReadWriteLock有兩個(gè)重要的方法:readLock()和writeLock(),分別用于獲取讀鎖和寫鎖。

我們看看示例代碼:

import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
public class ReadWriteLockExample {  
    private final ReadWriteLock lock = new ReentrantReadWriteLock();  
    private int data;  
  
    public void readData() {  
        lock.readLock().lock(); // 獲取讀鎖  
        try {  
            // 讀取共享資源  
            System.out.println("Reading data: " + data);  
        } finally {  
            lock.readLock().unlock(); // 釋放讀鎖  
        }  
    }  
  
    public void writeData(int newData) {  
        lock.writeLock().lock(); // 獲取寫鎖  
        try {  
            // 修改共享資源  
            this.data = newData;  
            System.out.println("Writing data: " + data);  
        } finally {  
            lock.writeLock().unlock(); // 釋放寫鎖  
        }  
    }  
}

在這個(gè)例子中,readData方法使用讀鎖來讀取data字段,而writeData方法使用寫鎖來修改data字段。當(dāng)多個(gè)線程調(diào)用readData時(shí),它們可以同時(shí)讀取數(shù)據(jù)而不會(huì)相互阻塞,除非有一個(gè)線程正在調(diào)用writeData并持有寫鎖。

需要注意的是,ReentrantReadWriteLock還有一個(gè)構(gòu)造方法,它接受一個(gè)布爾值參數(shù)fair,用于指定鎖是否應(yīng)該是公平的。如果設(shè)置為true,則等待時(shí)間最長(zhǎng)的線程將優(yōu)先獲得鎖。但是,公平鎖可能會(huì)降低性能,因?yàn)樾枰S護(hù)一個(gè)有序的等待隊(duì)列。

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2019-11-28 16:00:06

重入鎖讀寫鎖樂觀鎖

2024-05-17 09:33:22

樂觀鎖CASversion

2019-01-04 11:18:35

獨(dú)享鎖共享鎖非公平鎖

2024-09-03 15:14:42

2025-04-23 08:45:00

悲觀鎖樂觀鎖并發(fā)控制機(jī)制

2020-09-16 07:56:28

多線程讀寫鎖悲觀鎖

2023-02-23 10:32:52

樂觀鎖

2021-03-30 09:45:11

悲觀鎖樂觀鎖Optimistic

2018-07-31 10:10:06

MySQLInnoDB死鎖

2020-07-06 08:03:32

Java悲觀鎖樂觀鎖

2009-09-25 16:43:44

Hibernate悲觀Hibernate樂觀

2023-08-17 14:10:11

Java開發(fā)前端

2023-07-05 08:18:54

Atomic類樂觀鎖悲觀鎖

2011-08-18 13:44:42

Oracle悲觀鎖樂觀鎖

2024-07-25 09:01:22

2019-04-19 09:48:53

樂觀鎖悲觀鎖數(shù)據(jù)庫(kù)

2019-05-05 10:15:42

悲觀鎖樂觀鎖數(shù)據(jù)安全

2010-08-18 09:00:38

數(shù)據(jù)庫(kù)

2020-10-22 08:21:37

樂觀鎖、悲觀鎖和MVC

2024-01-05 16:43:30

數(shù)據(jù)庫(kù)線程
點(diǎn)贊
收藏

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