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, 尝试获得写锁会导致死锁, 必须先释放读锁, 即不支持锁升级