第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

讀寫鎖 ReentrantReadWriteLock

1. 前言

本節(jié)內(nèi)容主要是對 Java 讀寫鎖 ReentrantReadWriteLock 進(jìn)行講解,本節(jié)內(nèi)容幾乎全部為重點(diǎn)知識,需要學(xué)習(xí)者對 ReentrantReadWriteLock 進(jìn)行理解和掌握。本節(jié)內(nèi)容的知識點(diǎn)如下:

  • ReentrantReadWriteLock 簡單介紹,對 ReentrantReadWriteLock 進(jìn)行一個總體的概括;
  • ReentrantReadWriteLock 的類結(jié)構(gòu),從 Java 層面了解 ReentrantReadWriteLock;
  • ReentrantReadWriteLock 的特點(diǎn),相比于上兩點(diǎn)知識,該知識點(diǎn)可視為重點(diǎn);
  • ReentrantReadWriteLock 讀鎖共享的性質(zhì)驗證,為本節(jié)核心內(nèi)容之一;
  • ReentrantReadWriteLock 讀寫互斥的性質(zhì)驗證,為本節(jié)核心內(nèi)容之一。

ReentrantReadWriteLock 在 Java 的鎖當(dāng)中也占據(jù)著十分重要的地位,在并發(fā)編程中使用頻率也是非常的高,一定要對本節(jié)內(nèi)容進(jìn)行細(xì)致的學(xué)習(xí)和掌握。

2. ReentrantReadWriteLock 介紹

JDK 提供了 ReentrantReadWriteLock 讀寫鎖,使用它可以加快效率,在某些不需要操作實例變量的方法中,完全可以使用讀寫鎖 ReemtrantReadWriteLock 來提升該方法的運(yùn)行速度。

定義:讀寫鎖表示有兩個鎖,一個是讀操作相關(guān)的鎖,也稱為共享鎖;另一個是寫操作相關(guān)的鎖,也叫排他鎖。

定義解讀:也就是多個讀鎖之間不互斥,讀鎖與寫鎖互斥、寫鎖與寫鎖互斥。在沒有線程 Thread 進(jìn)行寫入操作時,進(jìn)行讀取操作的多個 Thread 都可以獲取讀鎖,而進(jìn)行寫入操作的 Thread 只有在獲取寫鎖后才能進(jìn)行寫入操作。即多個 Thread 可以同時進(jìn)行讀取操作,但是同一時刻只允許一個 Thread 進(jìn)行寫入操作。

3. ReentrantReadWriteLock 的類結(jié)構(gòu)

ReentrantReadWriteLock 是接口 ReadWriteLock 的子類實現(xiàn),通過 JDK 的代碼可以看出這一實現(xiàn)關(guān)系。

public class ReentrantReadWriteLock
        implements ReadWriteLock, java.io.Serializable{}

我們再來看下接口 ReadWriteLock,該接口只定義了兩個方法:

public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
}

通過調(diào)用相應(yīng)方法獲取讀鎖或?qū)戞i,可以如同使用 Lock 接口一樣使用。

4. ReentrantReadWriteLock 的特點(diǎn)

性質(zhì) 1 :可重入性。

ReentrantReadWriteLock 與 ReentrantLock 以及 synchronized 一樣,都是可重入性鎖,這里不會再多加贅述所得可重入性質(zhì),之前已經(jīng)做過詳細(xì)的講解。

性質(zhì) 2 :讀寫分離。

我們知道,對于一個數(shù)據(jù),不管是幾個線程同時讀都不會出現(xiàn)任何問題,但是寫就不一樣了,幾個線程對同一個數(shù)據(jù)進(jìn)行更改就可能會出現(xiàn)數(shù)據(jù)不一致的問題,因此想出了一個方法就是對數(shù)據(jù)加鎖,這時候出現(xiàn)了一個問題:

線程寫數(shù)據(jù)的時候加鎖是為了確保數(shù)據(jù)的準(zhǔn)確性,但是線程讀數(shù)據(jù)的時候再加鎖就會大大降低效率,這時候怎么辦呢?那就對寫數(shù)據(jù)和讀數(shù)據(jù)分開,加上兩把不同的鎖,不僅保證了正確性,還能提高效率。

性質(zhì) 3 :可以鎖降級,寫鎖降級為讀鎖。

線程獲取寫入鎖后可以獲取讀取鎖,然后釋放寫入鎖,這樣就從寫入鎖變成了讀取鎖,從而實現(xiàn)鎖降級的特性。

圖片描述

性質(zhì) 4 :不可鎖升級。

線程獲取讀鎖是不能直接升級為寫入鎖的。需要釋放所有讀取鎖,才可獲取寫鎖。

圖片描述

5. ReentrantReadWriteLock 讀鎖共享

我們之前說過,ReentrantReadWriteLock 之所以優(yōu)秀,是因為讀鎖與寫鎖是分離的,當(dāng)所有的線程都為讀操作時,不會造成線程之間的互相阻塞,提升了效率,那么接下來,我們通過代碼實例進(jìn)行學(xué)習(xí)。

場景設(shè)計

  • 創(chuàng)建三個線程,線程名稱分別為 t1,t2,t3,線程實現(xiàn)方式自行選擇;
  • 三個線程同時運(yùn)行獲取讀鎖,讀鎖成功后打印線程名和獲取結(jié)果,并沉睡 2000 毫秒,便于觀察其他線程是否可共享讀鎖;
  • finally 模塊中釋放鎖并打印線程名和釋放結(jié)果;
  • 運(yùn)行程序,觀察結(jié)果。

結(jié)果預(yù)期:三條線程能同時獲取鎖,因為讀鎖共享。

實例

public class DemoTest {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 讀寫鎖
    private int i;
    public String readI() {
        try {
            lock.readLock().lock();// 占用讀鎖
            System.out.println("threadName -> " + Thread.currentThread().getName() + " 占用讀鎖,i->" + i);
            Thread.sleep(2000);
        } catch (InterruptedException e) {

        } finally {
            System.out.println("threadName -> " + Thread.currentThread().getName() + " 釋放讀鎖,i->" + i);
            lock.readLock().unlock();// 釋放讀鎖
        }
        return i + "";
    }

    public static void main(String[] args) {
        final DemoTest demo1 = new DemoTest();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                demo1.readI();
            }
        };
        new Thread(runnable, "t1"). start();
        new Thread(runnable, "t2"). start();
        new Thread(runnable, "t3"). start();
    }
}

結(jié)果驗證

threadName -> t1 占用讀鎖,i->0
threadName -> t2 占用讀鎖,i->0
threadName -> t3 占用讀鎖,i->0
threadName -> t1 釋放讀鎖,i->0
threadName -> t3 釋放讀鎖,i->0
threadName -> t2 釋放讀鎖,i->0

結(jié)果分析:從結(jié)果來看,t1,t2,t3 均在同一時間獲取了鎖,證明了讀鎖共享的性質(zhì)。

6. ReentrantReadWriteLock 讀寫互斥

當(dāng)共享變量有寫操作時,必須要對資源進(jìn)行加鎖,此時如果一個線程正在進(jìn)行讀操作,那么寫操作的線程需要等待。同理,如果一個線程正在寫操作,讀操作的線程需要等待。

場景設(shè)計:細(xì)節(jié)操作不詳細(xì)闡述,看示例代碼即可。

  • 創(chuàng)建兩個線程,線程名稱分別為 t1,t2;
  • 線程 t1 進(jìn)行讀操作,獲取到讀鎖之后,沉睡 5000 毫秒;
  • 線程 t2 進(jìn)行寫操作;
  • 開啟 t1,1000 毫秒后開啟 t2 線程;
  • 運(yùn)行程序,觀察結(jié)果。

結(jié)果預(yù)期:線程 t1 獲取了讀鎖,在沉睡的 5000 毫秒中,線程 t2 只能等待,不能獲取到鎖,因為讀寫互斥。

實例

public class DemoTest {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 讀寫鎖
    private int i;
    public String readI() {
        try {
            lock.readLock().lock();// 占用讀鎖
            System.out.println("threadName -> " + Thread.currentThread().getName() + " 占用讀鎖,i->" + i);
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        } finally {
            System.out.println("threadName -> " + Thread.currentThread().getName() + " 釋放讀鎖,i->" + i);
            lock.readLock().unlock();// 釋放讀鎖
        }
        return i + "";
    }

    public void addI() {
        try {
            lock.writeLock().lock();// 占用寫鎖
            System.out.println("threadName -> " + Thread.currentThread().getName() + " 占用寫鎖,i->" + i);
            i++;
        } finally {
            System.out.println("threadName -> " + Thread.currentThread().getName() + " 釋放寫鎖,i->" + i);
            lock.writeLock().unlock();// 釋放寫鎖
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final DemoTest demo1 = new DemoTest();
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo1.readI();
            }
        }, "t1"). start();
        Thread.sleep(1000);
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo1.addI();
            }
        }, "t2"). start();
    }
}

結(jié)果驗證

threadName -> t1 占用讀鎖,i->0
threadName -> t1 釋放讀鎖,i->0
threadName -> t2 占用寫鎖,i->0
threadName -> t2 釋放寫鎖,i->1

結(jié)果解析:驗證成功,在線程 t1 沉睡的過程中,寫鎖 t2 線程無法獲取鎖,因為鎖已經(jīng)被讀操作 t1 線程占據(jù)了。

7. 小結(jié)

本節(jié)內(nèi)容只要是對讀寫鎖 ReentrantReadWriteLock 進(jìn)行的比較細(xì)致的講解,對于本節(jié)的內(nèi)容幾乎通篇為重點(diǎn)內(nèi)容。

其中核心知識點(diǎn)為讀鎖共享和讀寫互斥的驗證,所有的知識點(diǎn)都是圍繞這兩個話題進(jìn)行講解的,有興趣的同學(xué)可以根據(jù)實例代碼進(jìn)行寫鎖互斥的驗證。唯一不同的地方就是創(chuàng)建兩個寫線程進(jìn)行寫鎖的獲取。

掌握本節(jié)知識點(diǎn),有助于我們在特定的場景下對讀寫鎖進(jìn)行應(yīng)用。