重入锁和读写锁

ReentrantLock,重入锁,支持重新进入的锁:即某线程在获取到锁之后,可以再次获取锁而不会被阻塞。

其主要特性如下:

  • 支持重入:通过组合自定义同步器来来实现重入特性

    • synchronized关键字也隐式地支持重进入,比如synchronized修饰的递归方法,在方法执行时,执行线程在获取了锁之后仍能连续多次地获得该锁,不会出现阻塞自己的情况;

  • 支持公平地获取锁:获取锁的顺序与请求锁的顺序是相同的,等待时间最长的线程最优先获取到锁。

  • 支持绑定多个Condition

非公平获取锁重进入的实现

final boolean nonfairTryAcquire(int acquires) {
      final Thread current = Thread.currentThread();
      int c = getState();
      if (c == 0) {
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }else if (current == getExclusiveOwnerThread()) {
        //如果是当前持有锁的线程再次获取锁,则将同步值进行增加并返回true
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
}

公平锁重进入的实现

与非公平获取锁的方法nonfairTryAcquire(int acquires)相比,多了一个hasQueuedPredecessors()判断:同步队列中当前节点(当前想要获取锁的线程)是否有前驱节点,如果该方法返回true,则表示有线程比当前线程更早地请求获取锁,因此需要前驱线程获取并释放锁之后才能继续获取锁。

公平锁保证了锁的获取按照FIFO原则,而代价是进行大量的线程切换; 非公平锁虽然可能造成线程“饥饿”(即某线程可能需要等很久才得到锁),但线程切换极少,可以保证更大的吞吐量。

ReentrantReadWriteLock

ReentrantLock在同一时刻,只允许一个线程进行访问(无论读还是写)。而读写锁是指:在同一时刻,允许多个线程进行读操作,而写操作则会阻塞其他所有的线程(无论是读还是写,都会被阻塞)。读写锁维护了一对锁:读锁和写锁,通过分离读锁和写锁,使得并发性能相比一般的排他锁有了很大的提升。

它的特性如下:

  • 重进入;

  • 公平性选择

  • 锁降级:写锁可以降级为读锁,

此外,ReentrantReadWriteLock还提供了一些便于外界监控其内部状态的方法,如下:

示例:使用ReentrantReadWriteLock实现Cache

TODO:读写锁的实现原理

Last updated