源码层面分析:
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
//实现同步逻辑的同步器,提供了所有锁相关的操作
private final Sync sync;
//默认构造函数,提供了非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 根据策略(公平,非公平)来构建重入锁
* @param fair true表示采用公平锁,false表示采用非公平锁
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
//获取锁,获取成功则返回,否则阻塞获取线程直到获取成功
public void lock() {
sync.lock();
}
//获取锁,获取成功则返回,否则阻塞获取线程直到获取成功;并响应中断,也就是说获取线程被Thread.interrupt()中断后,该方法会抛出InterruptedException并返回。
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 尝试获取锁,不管成功,失败都立即返回,不会阻塞
* @return true表示获取成功,false表示失败
*/
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
/**
* 尝试获取锁,获取成功则返回,否则等待timeout时间返回
* @param timeout 等待获取锁的超时时间
* @param unit 时间单位
* @return true表示获取成功,false表示超时时间到达仍然获取失败
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
//释放锁,该方法不会阻塞
public void unlock() {
sync.release(1);
}
/**
* 获取一个条件对象
* @return 条件对象
*/
public Condition newCondition() {
return sync.newCondition();
}
Sync内部类:
//同步抽象类,基于AQS实现
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
//具体由子类NoFairSync,FairSync实现
abstract void lock();
/**
* 非公平的方式尝试获取资源
* @param acquires 资源个数
* @return true表示获取成功,false获取失败
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取资源状态,volatile读
int c = getState();
//0表示初始状态或者锁释放状态,可以直接获取资源
if (c == 0) {
//CAS判断资源获取是否成功
if (compareAndSetState(0, acquires)) {
//获取成功则设置当前线程为资源(锁)的持有线程
setExclusiveOwnerThread(current);
return true;
}
}
//如果当前线程为持有锁的线程,可以直接操作资源,体现重入性
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//其他状态说明资源已被其他占用无法获取
return false;
}
/**
* 尝试释放资源
* @param releases 资源个数
* @return true表示释放成功,false释放失败
*/
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
//如果当前线程不为持有资源的线程,则抛出异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果释放后,资源的个数为0表示释放成功
if (c == 0) {
free = true;
//设置资源的独占线程为null,此时没有线程占用资源
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
/**
* 判断当前线程是否持有资源
* @return true表示是,false表示否
*/
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
/**
* 获取条件对象
* @return 新的条件对象
*/
final ConditionObject newCondition() {
return new ConditionObject();
}
/**
* 获取持有资源的线程
* @return 持有资源的线程
*/
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
/**
* 获取持有资源的个数
* @return 持有资源的个数
*/
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
/**
* 获取资源是否被线程占用
* @return true表示是,false否
*/
final boolean isLocked() {
return getState() != 0;
}
}
ReentrantLock内部基于Sync提供了非公平锁和公平锁的实现。
非公平锁
//非公平锁继承自Sync
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* 非公平锁提供的锁定方法
*/
final void lock() {
//先尝试CAS获取操作,获取成功则设置当前线程为资源持有线程并返回
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//获取失败则进入AQS的acquire逻辑,排队获取资源
acquire(1);
}
/**
* 非公平的方法尝试获取资源,AQS对外提供的需要实现方法
* @param acquires资源个数
* @return true表示是,false否
*/
protected final boolean tryAcquire(int acquires) {
//用Sync类的非公平方式尝试获取资源
return nonfairTryAcquire(acquires);
}
}
公平锁:
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
/**
* 公平锁提供的锁定方法
*/
final void lock() {
//排队获取资源,体现公平性
acquire(1);
}
/**
* 公平的方式尝试获取资源
* @param acquires资源个数
* @return true表示是,false否
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//0表示当前可以直接获取资源
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;
}
}
**总结:**非公平主要体现在资源获取时,如果获取线程发现当前资源可以获取成功(其他线程释放了资源)那就直接获取返回,而此时可能有其他线程先于当前线程在排队获取,那么对于这部分线程来说是“不公平”的,没有体现先到先得的原则。反之,就是公平锁,先排队的线程先获取锁,不存在插队的情况,体现了公平性,所以叫公平锁。
ReentrantLock默认使用非公平方式提供锁的获取和释放,可以看到相比公平模式,非公平模式获取锁的效率更高,因为在非公平模式下如果能够获取锁成功则线程不需要再排队,而在公平模式下,所有线程都必须排队获取锁,所以从当前获取锁的线程的角度非公平模式效率更高。还有一个地方需要说明的是:ReentrantLock是可重入锁,也就是说同一个线程获取锁后可再次重复获取锁无需阻塞。
典型应用场景:
class X {
private final ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void m() {
lock.lock(); // 获取锁
try {
try {
//必须先获取锁才能执行条件等待,其他线程需要执行condition.signal()方法,来唤醒等待线程
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行具体业务方法
} finally {
lock.unlock() //释放锁,必须在finally块中,防止发生异常时未执行释放锁操作,导致其他线程无法获取锁
}
}
}}