ReentrantReadWriteLock 类, 顾名思义, 是一种读写锁, 它是 ReadWriteLock 接口的直接实现, 该类在内部实现了具体独占锁特点的写锁, 以及具有共享锁特点的读锁, 和 ReentrantLock 一样, ReentrantReadWriteLock 类也是通过定义内部类实现AQS框架的API来实现独占/共享的功能.

ReentrantLock 属于排他锁, 这些锁在同一时刻只允许一个线程进行访问, 但是在大多数场景下, 大部分时间都是提供读服务, 而写服务占有的时间较少. 而且, 读服务不存在数据竞争问题, 如果一个线程在读时禁止其他线程读势必会导致性能降低. 所以就提供了读写锁.

读写锁维护着一对锁, 一个读锁和一个写锁. 通过分离读锁和写锁, 使得并发性比一般的排他锁有了较大的提升:

  • 在同一时间, 可以允许多个读线程同时访问.
  • 但是, 在写线程访问时, 所有读线程和写线程都会被阻塞.

读写锁的主要特性:

  • 公平性:支持公平性和非公平性.
  • 重入性:支持重入. 读写锁最多支持 65535 个递归写入锁和 65535 个递归读取锁.
  • 锁降级:遵循获取写锁, 再获取读锁, 最后释放写锁的次序, 如此写锁能够降级成为读锁.

ReadWriteLock

读写锁 ReentrantReadWriteLock 实现接口 ReadWriteLock, 该接口维护了一对相关的锁, 一个用于只读操作, 另一个用于写入操作. 只要没有 writer, 读取锁可以由多个 reader 线程同时保持. 写入锁是独占的.

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

ReadWriteLock 定义了两个方法. readLock() 返回用于读操作的锁, writeLock() 返回用于写操作的锁.

ReentrantReadWriteLock

java.util.concurrent.locks.ReentrantReadWriteLock 定义如下.

/** 内部类  读锁 */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** 内部类  写锁 */
private final ReentrantReadWriteLock.WriteLock writerLock;

final Sync sync;

/** 使用默认(非公平)的排序属性创建一个新的 ReentrantReadWriteLock */
public ReentrantReadWriteLock() {
    this(false);
}

/** 使用给定的公平策略创建一个新的 ReentrantReadWriteLock */
public ReentrantReadWriteLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
    readerLock = new ReadLock(this);
    writerLock = new WriteLock(this);
}

/** 返回用于写入操作的锁 */
@Override
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
/** 返回用于读取操作的锁 */
@Override
public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }

abstract static class Sync extends AbstractQueuedSynchronizer {
    /**
     * 省略其余源代码
     */
}
public static class WriteLock implements Lock, java.io.Serializable {
    /**
     * 省略其余源代码
     */
}

public static class ReadLock implements Lock, java.io.Serializable {
    /**
     * 省略其余源代码
     */
}

ReentrantReadWriteLockReentrantLock 一样, 其锁主体依然是 Sync, 它的读锁、写锁都是依靠 Sync 来实现的.

所以 ReentrantReadWriteLock 实际上只有一个锁, 只是在获取读取锁和写入锁的方式上不一样而已, 它的读写锁其实就是两个类: ReadLockwriteLock, 这两个类都是lock实现.

ReentrantLock 中, 使用 Sync ( 实际是 AQS ) 的 int 类型的 state 来表示同步状态, 表示锁被一个线程重复获取的次数.

但是, 读写锁 ReentrantReadWriteLock 内部维护着一对读写锁, 如果要用一个变量维护多种状态, 需要采用 “按位切割使用” 的方式来维护这个变量, 将其切分为两部分: 高16为表示读, 低16为表示写.


sc_ik
127 声望8 粉丝

我用时间换到了什么