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();
    }

}

在释放写锁之前获取读锁,此时其他线程在读线程释放读锁之前无法进行写操作,进而保证了线程安全性。

猜你喜欢

转载自blog.csdn.net/qq_22866497/article/details/80851567