JUC- 读写锁

75 阅读3分钟

ReadWriteLock

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

A ReadWriteLock维护一对关联的locks ,一个用于只读操作,一个用于写入。

  • read lock可以由多个阅读器线程同时进行,只要没有writer。
  • write lock是独家的。

读锁是共享锁,写锁是排他锁。 读读可以共存。读写,写写不能共存。

ReadWrite的实现类是ReentrantReadWriteLock

ReentrantReadWriteLock

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

具有以下属性:

可选的策略:

此类不会强加读卡器或写入器优先顺序锁定访问。 但是,它确实支持可选的公平政策。

public ReentrantReadWriteLock() {
        this(false);//默认不公平锁
    }
public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();//根据fair选择
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

非公平模式(默认)

线程对锁进行争抢,吞吐量大

公平模式

类似于排队,分配给等待最久的线程(写优先)

如果写锁定或有等待的写入程序线程,尝试获取公平读锁(不可重入)的线程将阻塞,直到最旧的当前正在等待的写入程序线程获取并释放写入锁之后,该线程才会获取读锁定。(没有其他线程的写锁或写请求) 当然,如果一个等待的作家放弃了等待,留下一个或多个阅读器线程作为队列中最长的服务器,其中写锁定空闲,那么这些读取器将被分配读取锁定。

尝试获取公平写入锁(非重入)的线程将阻止,除非读锁定和写锁定都是空闲的(这意味着没有等待线程)。 (请注意,无阻塞ReentrantReadWriteLock.ReadLock.tryLock()和ReentrantReadWriteLock.WriteLock.tryLock()方法不符合此公平的设置,如果可能,将立即获取锁定,而不管等待线程。)

可重入

可重入: 拥有锁的线程再次重复申请同一个锁,

此锁允许reader和writer按照 ReentrantLock 的样式重新获取读/写锁。在写线程保持的所有写锁都已释放后,才允许重入reader使用读锁 writer可以获取读取锁,但reader不能获取写入锁。

public class RWTest {
    private static ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
    public static void main(String[] args) {
        RWTest rwTest = new RWTest();
        new Thread(()->{rwTest.write();}).start();
    }
    public synchronized void read(){
        lock.readLock().lock();
        System.out.println("read come in");
        lock.readLock().unlock();
        System.out.println("read go out");
    }
    public synchronized void write(){
        // 在写时调用读
        lock.writeLock().lock();
        System.out.println("w come in");
        read();
        lock.writeLock().unlock();
        System.out.println("w go out");
    }
}
w come in
read come in
read go out
w go out
public class RWTest {
    private static ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
    public static void main(String[] args) {
        RWTest rwTest = new RWTest();
        new Thread(()->{rwTest.read();}).start();
    }
    public synchronized void read(){
        lock.readLock().lock();
        System.out.println("read come in");
        //读时写-> 死锁
        write();
        lock.readLock().unlock();
        System.out.println("read go out");
    }

锁降级

重入还允许从写入锁降级为读取锁,实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。

允许写锁降级为读锁,但是从读锁定升级到写锁是不可能的

public class RWTest {
    private static ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
    public static void main(String[] args) {
        RWTest rwTest = new RWTest();
        new Thread(()->{rwTest.write();}).start();
    }
    public synchronized void read(){
        lock.readLock().lock();
        System.out.println("read come in");
        lock.readLock().unlock();
        System.out.println("read go out");

    }
    public synchronized void write(){
        lock.writeLock().lock();
        System.out.println("w come in");
        lock.readLock().lock();
        System.out.println("read was lock");
        lock.writeLock().unlock();
        System.out.println("w go out");
        lock.readLock().unlock();
        System.out.println("read unlock");
    }
w come in
read was lock
w go out
read unlock

可中断

中断: 在等待锁的时候可以放弃等待 读锁和写锁都支持中断

Condition支持

写入锁提供了一个Condition实现,这个Condition当然只能用于写锁。

public Condition newCondition() {
            return sync.newCondition();
        }

读锁不支持Condition和readLock().newCondition()抛出UnsupportedOperationException异常 。

监控

提供确定锁是否被持有等辅助方法