【讀寫(xiě)鎖】java ReentrantReadWriteLock學(xué)習(xí)

ReadWriteLock 是什么

  • 首先明確一下,不是說(shuō) ReentrantLock 不好,只是 ReentrantLock 某些時(shí)候有局限。
    • 如果使用 ReentrantLock,可能本身是為了防止線程 A 在寫(xiě)數(shù)據(jù)、線程 B 在讀數(shù)據(jù)造成的數(shù)據(jù)不一致,
  • 但這樣,如果線程 C 在讀數(shù)據(jù)、線程 D 也在讀數(shù)據(jù),讀數(shù)據(jù)是不會(huì)改變數(shù)據(jù)的,沒(méi)有必要加鎖,但是還是加鎖了,降低了程序的性能。因?yàn)檫@個(gè),才誕生了讀寫(xiě)鎖 ReadWriteLock。
  • ReadWriteLock 是一個(gè)讀寫(xiě)鎖接口,讀寫(xiě)鎖是用來(lái)提升并發(fā)程序性能的鎖分離技術(shù),
  • ReentrantReadWriteLock 是 ReadWriteLock 接口的一個(gè)具體實(shí)現(xiàn),實(shí)現(xiàn)了讀寫(xiě)的分離,讀鎖是共享的,寫(xiě)鎖是獨(dú)占的,讀和讀之間不會(huì)互斥,讀和寫(xiě)、寫(xiě)和讀、寫(xiě)和寫(xiě)之間才會(huì)互斥,提升了讀寫(xiě)的性能。

讀寫(xiě)鎖的意義

ReadWriteLock 接口的一個(gè)具體實(shí)現(xiàn),實(shí)現(xiàn)了讀寫(xiě)的分離,讀鎖是共享的,寫(xiě)鎖是獨(dú)占的,讀和讀之間不會(huì)互斥,讀和寫(xiě)、寫(xiě)和讀、寫(xiě)和寫(xiě)之間才會(huì)互斥,提升了讀寫(xiě)的性能。

讀寫(xiě)鎖特性: 3`

(1)公平選擇性:支持非公平(默認(rèn))和公平的鎖獲取方式,吞吐量還是非公平優(yōu)于公平。
(2)重進(jìn)入:讀鎖和寫(xiě)鎖都支持線程重進(jìn)入。
(3)鎖降級(jí):遵循獲取寫(xiě)鎖、獲取讀鎖再釋放寫(xiě)鎖的次序,寫(xiě)鎖能夠降級(jí)成為讀鎖。

使用

1、基本使用案例

package lockTest.reentrantReadWriteLock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author: WalkerShen
 * @DATE: 2022/3/22
 * @Description: 讀寫(xiě)鎖
 **/
public class ReadWriteLockTest {
    /**
     * public ReentrantReadWriteLock(boolean fair)
     * ReentrantReadWriteLock也可以實(shí)現(xiàn)公平鎖和非公平鎖
     */
    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private final static Lock readLock = readWriteLock.readLock();
    private final static Lock writeLock = readWriteLock.writeLock();
    private final static List<Integer> dataList = new ArrayList<>();

    public static void main(String[] args) {
        new Thread(() -> write()).start();
        new Thread(() -> write()).start();
        new Thread(() -> read()).start();
        new Thread(() -> read()).start();
    }


    /**
     * 讀方法
     */
    public static void read() {
        readLock.lock();
        for (Integer data : dataList) {
            System.out.println(Thread.currentThread().getName() + "讀取數(shù)據(jù):" + data);
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            readLock.unlock();
        }


    }

    /**
     * 寫(xiě)方法
     */
    public static void write() {
        writeLock.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "寫(xiě)數(shù)據(jù):" + i);
            dataList.add(i);
        }
        writeLock.unlock();

    }

}

結(jié)果:

Thread-0寫(xiě)數(shù)據(jù):0
Thread-0寫(xiě)數(shù)據(jù):1
Thread-0寫(xiě)數(shù)據(jù):2
Thread-0寫(xiě)數(shù)據(jù):3
Thread-0寫(xiě)數(shù)據(jù):4
Thread-1寫(xiě)數(shù)據(jù):0
Thread-1寫(xiě)數(shù)據(jù):1
Thread-1寫(xiě)數(shù)據(jù):2
Thread-1寫(xiě)數(shù)據(jù):3
Thread-1寫(xiě)數(shù)據(jù):4
Thread-2讀取數(shù)據(jù):0
Thread-2讀取數(shù)據(jù):1
Thread-2讀取數(shù)據(jù):2
Thread-3讀取數(shù)據(jù):0
Thread-2讀取數(shù)據(jù):3
Thread-3讀取數(shù)據(jù):1
Thread-2讀取數(shù)據(jù):4
Thread-3讀取數(shù)據(jù):2
Thread-2讀取數(shù)據(jù):0
Thread-3讀取數(shù)據(jù):3
Thread-2讀取數(shù)據(jù):1
Thread-3讀取數(shù)據(jù):4
Thread-2讀取數(shù)據(jù):2
Thread-3讀取數(shù)據(jù):0
Thread-2讀取數(shù)據(jù):3
Thread-3讀取數(shù)據(jù):1
Thread-2讀取數(shù)據(jù):4
Thread-3讀取數(shù)據(jù):2
Thread-3讀取數(shù)據(jù):3
Thread-3讀取數(shù)據(jù):4

從結(jié)果中可以發(fā)現(xiàn),寫(xiě)操作的時(shí)候只有Thread-0執(zhí)行完之后才到Thread-1,
而讀操作的時(shí)候,Thread-2和Thread-3是交替進(jìn)行的

2、鎖升級(jí)

在線程中,寫(xiě)鎖的級(jí)別是大于讀鎖的,意思是如果不釋放讀鎖,去獲取寫(xiě)鎖,是獲取不到的,會(huì)導(dǎo)致線程阻塞
但是如果持有寫(xiě)鎖,去獲取讀鎖,是可以獲取到的
意思就是說(shuō),讀鎖到寫(xiě)鎖,是需要釋放后才可以升級(jí)的

package lockTest.reentrantReadWriteLock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author: WalkerShen
 * @DATE: 2022/3/22
 * @Description: 讀寫(xiě)鎖結(jié)合
 **/
public class ReadWriteCombineTest {

    private static ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    /**
     * public static class ReadLock implements Lock, java.io.Serializable
     * 因?yàn)镽eadLock和WriteLock都是靜態(tài)內(nèi)部類,所以需要添加static修飾
     */
    private static Lock readLock=readWriteLock.readLock();
    private static Lock writeLock=readWriteLock.writeLock();
    private static String data=null;

    public static void main(String[] args) {
//        new Thread(()->notReleaseReadLock()).start();

        new Thread(()->releaseReadLock()).start();
    }

    /**
     * 讀寫(xiě)結(jié)合
     * 在寫(xiě)鎖操作的時(shí)候,沒(méi)有釋放讀鎖
     * 這個(gè)時(shí)候就會(huì)阻塞
     */
    public static void notReleaseReadLock(){
        readLock.lock();
        if(data==null){
            writeLock.lock();
            data="aaaa";
            System.out.println(data);
            writeLock.unlock();
        }
        readLock.unlock();
    }


    /**
     * 讀寫(xiě)結(jié)合
     * 在獲取寫(xiě)鎖之前先釋放掉讀鎖
     * 輸出結(jié)果:aaaa
     */
    public static void releaseReadLock(){
        readLock.lock();
        if(data==null){
            readLock.unlock();
            writeLock.lock();
            data="aaaa";
            System.out.println(data);
            writeLock.unlock();
        }
    }


}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容