ReentrantLock原理

ReentrantLock基于AQS(Q:队列 S:同步): CAS修改state, 如果修改state成功, 则表示获得了该锁, 线程继续执行, 否则表示该锁已经被其他线程获得, 本线程被插入队列并挂起.

1.线程尝试修改state, 成功则继续执行, 否则进入2

2.把本线程封装成一个node插入队尾, 进行自旋:如果当前node处于队首, 那么再次tryAcquire获取锁, 如果成功, 线程避免被挂起并继续执行, 否则进入3

3.判断前一个node是否已经取消获得锁, 是则删除前一个node, 否则将线程挂起,进入等待唤醒->4

4.线程被唤醒, 先检查自身interrupt状态, 如果被被中断则抛出InterruptedException并退出队列, 否则tryAcquire竞争锁

关于公平锁和非公平锁

new ReentrantLock(true);

非公平锁在4时, 调用tryAcquire获得锁, 这时如果有其他线程调用tryAcquire是竞争的. 并不能保证哪个线程获得锁

而公平锁则是在1时,先判断队列是否为空,如果不为空, 则不会直接调用tryAcquire,而是进入队列, 这样就不会有线程竞争问题

但是公平锁性能不如非公平锁, 非公平锁在有新线程竞争锁时, 优先是给新线程的, 这样就避免了新线程的挂起

关于读写锁

核心是三个状态: 读锁数 / 独占锁线程 / 锁重入数

 1. 获得写锁:

  1> 读锁数量为0

  2> 独占线程是本线程则重入数+acquires或者没有独占线程则设置独占线程为本线程

2.获得读锁

  1> 如果独占线程为本线程或者独占线程为null则读锁数+1

锁降级:

  如果已经获得写锁, 那么由于独占线程是本线程可以直接获得读锁, 可直接获得读锁, 此时线程有 读/写 两个锁, 需要释放写锁完成降级

  如果已经获得读锁, 那么由于读锁数量不为0, 尝试获得写锁会导致死锁, 必须先释放读锁, 即不支持锁升级

原文地址:https://www.cnblogs.com/bianzy/p/6576404.html