《Java并发编程:Lock》 《java 锁 Lock接口详解》
《[死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁]》)
锁的类型目前感觉可以分成两大类:synchronized 关键字,以及 Lock, ReadWriteLock 锁以及 Reentrant 为前缀修饰的实现类 (ReentrantLock, ReentrantReadWriteLock);
其他角度来看,按照不同分类类型的锁:
可重入性的原理:参考《深入理解 Java 虚拟机》P391 可重入锁和不可重入:参考《Java不可重入锁和可重入锁理解》 对于一个对象,进入对象锁的代码域之后,线程对该锁进行计数。没有进入锁时,该锁的计数值为 0。第一个获取到该锁的线程获得该对象锁,此后每多一个线程对该锁进行申请,则计数值 +1。每当有一个线程释放了这个锁,则该锁对应的计数值 -1。直到这个锁的计数值重新回到 0,其他线程才可以获取到该锁的所有权。 我对于对象锁的理解:
不可重入锁:以可重入的对立面理解即可:对于某个 Lock 的实现,如果该 Lock 被线程A锁住,线程A的其他对象想要获取该 Lock,但由于在此之前 Lock 已经被锁住,所以这里不能获取到该 Lock。总之感觉不可重入锁并不是一种合适的 Lock 的类型。
不可重入锁的代码实例如下:
public class Lock {
private boolean isLocked = false;
public synchronized void lock() throws InterruptedException {
while(isLocked) {
wait();
}
isLocked = true;
}
public synchronized void unlock() {
isLocked = false;
notify();
}
}
public class Count {
Lock lock = new Lock();
public void print() {
lock.lock();
doAdd();
lock.unlock();
}
public void doAdd() {
lock.lock();
//do something
lock.unlock();
}
}
Lock 接口主要有六个方法:
// 获取锁
void lock();
// 获取锁,可中断
void lockInterruptibly() throws InterruptedException;
// 尝试获取锁;如果没有获取到,则返回 false;如果获取到则返回 true
boolean tryLock();
// 尝试在某段时间内获取锁,如果等待一段时间仍没有获取到则返回 false;
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 释放锁
void unlock();
// 条件锁
Condition newCondition();
为什么ReentrantLock默认采用的是非公平模式?因为非公平模式效率比较高。非公平模式会在一开始就尝试两次获取锁,如果当时正好 state 的值为 0,它就会成功获取到锁,少了排队导致的阻塞/唤醒过程,并且减少了线程频繁的切换带来的性能损耗。
同时非公平模式也存在弊端。非公平模式有可能会导致一开始排队的线程一直获取不到锁,导致线程饿死。
公平锁与非公平锁在源码上的区别: