可重入锁,就是支持重入的锁,它表示该锁能够支持一个线程对资源的重复加锁。除此之外,该锁还支持获取公平锁和非公平锁。
在绝对的时间上,先对锁进行获取请求的一定先被满足,那么这个锁是公平锁,反之,是非公平锁。
公平锁往往没有非公平锁的效率高,但是,并不是任何场景都是以TPS作为唯一的指标,公平锁能够减少“饥饿”的概率。
实现重进入
重进入是指任意线程在获取到锁后能够再次获取该锁而不会被阻塞,这需要解决两个问题:
1)线程再次获取锁。锁需要识别获取锁的线程,如果是则再次获取成功
2)锁的最终释放。线程重复n次获取了锁,随后在第n次释放锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁释放时,计数自减,当计数等于0时表示锁已经成功释放。
公平与非公平获取锁的区别
公平性与否是针对获取锁而言的,如果一个锁是公平的,那么获取锁的顺序就应该符合请求的绝对顺序,也就是FIFO。
非公平锁的获取
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {//cas获取锁if (compareAndSetState(0, acquires)) {//设置当前线程为排它锁拥有线程setExclusiveOwnerThread(current);return true;}}//如果当前线程是拥有排它锁的线程else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");//计数器自增setState(nextc);return true;}return false;}
公平锁的获取
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
public final boolean hasQueuedPredecessors() {// 这个的正确性取决于头部在尾部和头部之前被初始化。如果当前线程在队列中的第一个,则它是准确的。Node t = tail; // Read fields in reverse initialization orderNode h = head;Node s;return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());}
锁的释放
protected final boolean tryRelease(int releases) {int c = getState() - releases;//拥有锁的线程不是当前线程,报错if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {//计数为0时,释放锁,将拥有锁的线程设置为nullfree = true;setExclusiveOwnerThread(null);}//更新计数setState(c);return free;}
