1. 程式人生 > >Java併發程式設計-讀寫鎖

Java併發程式設計-讀寫鎖

1.認識讀寫鎖

讀寫鎖既是一個排他鎖也是一個共享鎖,讀鎖是共享鎖,寫鎖是排他鎖。讀操作可以共存,讀操作和寫操作互斥,寫操作和寫操作之間互斥。下面是一個使用例子:

public class Demo {
    private Map<String, Object> map = new HashMap<>();

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private Lock readLock = readWriteLock.readLock();

    private Lock writeLock = readWriteLock.writeLock();

    public Object get(String key) {
        readLock.lock();
        try {
            return map.get(key);
        } finally {
            readLock.unlock();
        }
    }

    public void set(String key, Object value) {
        writeLock.lock();
        try {
            map.set(key, value);
        } finally {
            writeLock.unlock();
        }
    }

}

2.讀寫鎖原理

讀寫鎖需要儲存三個狀態,寫鎖重入的次數,讀鎖的個數,每個讀鎖重入的次數。記錄寫鎖和讀鎖重入的次數是為了實現鎖的可重入,記錄讀鎖的個數是為了在沒有執行緒持有讀鎖時,寫執行緒能進行寫操作。

3.鎖降級

鎖降級是指鎖降級為讀鎖。在寫鎖沒有釋放的時候,獲取到讀鎖,再釋放寫鎖。

我們先來看一個會引起問題的加鎖方式。

public class Demo {
    private Map<String, Object> map = new HashMap<>();

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private Lock readLock = readWriteLock.readLock();

    private Lock writeLock = readWriteLock.writeLock();

    private boolean isUpdate;

    public void readWrite() {
        readLock.lock(); // 保證可以isUpdate可以拿到最新值
        if (isUpdate) {
            readLock.unlock();
            writeLock.lock(); // 若干個寫執行緒阻塞在這一行
            map.put("a","b");
            writeLock.unlock();// 寫執行緒釋放鎖
        }

        Object object = map.get("a");// 讀執行緒讀取值
    }

}

當寫執行緒釋放鎖,其他寫執行緒競爭到鎖後,讀執行緒此時讀取到的可能是髒值。

鎖降級方式加鎖:

public class Demo2 {
    private Map<String, Object> map = new HashMap<>();

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private Lock readLock = readWriteLock.readLock();

    private Lock writeLock = readWriteLock.writeLock();

    private boolean isUpdate;

    public void readWrite() {
        readLock.lock(); // 保證可以isUpdate可以拿到最新值
        if (isUpdate) {
            readLock.unlock();
            writeLock.lock();
            map.put("a","b");
            readLock.lock();
            writeLock.unlock();

        }

        Object object = map.get("a");
        readLock.unlock();
    }

}

在釋放寫鎖之前獲取讀鎖,此時其他執行緒在讀執行緒釋放讀鎖之前無法進行寫操作,進而保證了執行緒安全性。