可重入锁- ReentrantLock
本章只分析 ReentrantLock,不分析 AQS 原理,AQS 从入门到精通传送门,ReentrantLock 的话源码还是比较简单的
类继承
// Lock 接口定义了加锁、释放锁的方法
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
}
类成员
类属性
// 就一个属性,Sync 是内部类继承自 AQS
private final Sync sync;
内部类
// 继承 AbstractQueuedSynchronizer
abstract static class Sync extends AbstractQueuedSynchronizer {
// 定义 lock 方法(ReentrantLock实现了Lock接口)
abstract void lock();
// 非公平方式获取锁(公平方式获取锁在子类 FairSync 里)
final boolean nonfairTryAcquire(int acquires){}
// 实现 AQS 释放锁的模板方法
protected final boolean tryRelease(int releases) {}
// 当前线程是否持有锁
protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); }
// 当前持有锁的线程是哪个
final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); }
// 当前线程重入次数(如果当前线程没获取锁返回0)
final int getHoldCount() { return isHeldExclusively() ? getState() : 0; }
}
/**
* 非公平锁
*/
static final class NonfairSync extends Sync {
// 实现 Sync 的 lock 方法
final void lock() { }
// 实现 AQS 的 tryAcquire(),获取锁,非公平方式获取
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
}
/**
* 公平锁
*/
static final class FairSync extends Sync {
// 实现 Sync 的 lock 方法
final void lock() { }
// 实现 AQS 的 tryAcquire(),获取锁,公平方式获取
protected final boolean tryAcquire(int acquires) { }
}
类方法
构造方法
// 无参构造(默认非公平锁)
public ReentrantLock() {
sync = new NonfairSync();
}
// 有参构造(true:公平锁;false:非公平锁)
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
// 获取锁(获取不到就线程入队并阻塞住)
public void lock() {
sync.lock();
}
// 获取锁(获取不到不会入队)
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
// 获取锁(获取不到不会入队,带超时时间)
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
// 释放锁
public void unlock() {
sync.release(1);
}
lock 加锁原理
非公平锁
ReentrantLock
// java.util.concurrent.locks.ReentrantLock.Sync#lock
public void lock() {
sync.lock(); // 这是个抽象方法,具体由子类实现:FairSync(公平)、NonfairSync(非公平)
}
NonfairSync
// java.util.concurrent.locks.ReentrantLock.NonfairSync#lock
final void lock() {
if (compareAndSetState(0, 1)) // 不讲武德,不看队列有没有线程在排队,而是直接尝试持有锁(插队)
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); // 插队失败的处理
}
AbstractQueuedSynchronizer
// java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire
public final void acquire(int arg) { // 这是AQS提供的标准的流程
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 3 个方法,核心
selfInterrupt();
}
addWaiter()、acquireQueued() 是 AQS 提供的,这里不展开说
这里只看 tryAcquire 怎么实现的,源码如下:
// java.util.concurrent.locks.ReentrantLock.NonfairSync#tryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // 获取 state
if (c == 0) { // 如果是 0,说明锁未被任何线程持有,尝试 CAS 修改 state
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) { // 如果不是 0,说明锁已经被其他线程持有,本来就该返回 false 了,但是可以重入
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
公平锁
公平锁和非公锁逻辑基本一致,就是在获取锁时多了一个条件 hasQueuedPredecessors(),除此之外都是一样的
hasQueuedPredecessors() 方法就是看当前是否有线程排队,如果没有才获取锁,严格恪守先进先出的特性
// java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire
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;
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer#hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
unlock 释放锁原理
ReentrantLock
// java.util.concurrent.locks.ReentrantLock#unlock
public void unlock() {
sync.release(1);
}
AbstractQueuedSynchronizer
// java.util.concurrent.locks.AbstractQueuedSynchronizer#release
public final boolean release(int arg) {
if (tryRelease(arg)) { // 释放锁
Node h = head; // 取出头结点
if (h != null && h.waitStatus != 0) // 是否有线程再等待获取锁,如果有就需要唤醒
unparkSuccessor(h); // AQS 提供,原来的头结点改为0后,唤醒线程,头结点会更新(头结点出队)
return true;
}
return false;
}
h != null:头结点为空,说明链表还未初始化,也表明没有其他线程在等待锁,不用唤醒下一个节点
h.waitStatus != 0:如果有其他线程等待锁,AQS 线程入队时,会把前驱节点状态改为 -1
所以如果等于0,也就是没有后继节点,也不用唤醒下一个节点的线程
唤醒后期节点 unparkSuccessor() 是 AQS 提供的,这里不赘述,看下怎么释放锁的,源码如下:
// 这个方法还是比较简单的,就是把 state -1
// java.util.concurrent.locks.ReentrantLock.Sync#tryRelease
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
使用示例
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
private int counter = 0;
public void increment() {
lock.lock(); // 获取锁
try {
counter++;
System.out.println(Thread.currentThread().getName() + " 增加计数器到: " + counter);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
}
public void performTask() {
// 尝试获取锁,如果锁不可用则立即返回
if (lock.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + " 获取到锁并执行任务");
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} else {
System.out.println(Thread.currentThread().getName() + " 无法获取锁,执行其他操作");
}
}
public static void main(String[] args) {
ReentrantLockExample example = new ReentrantLockExample();
Runnable task1 = () -> {
for (int i = 0; i < 5; i++) {
example.increment();
}
};
Runnable task2 = () -> {
for (int i = 0; i < 5; i++) {
example.performTask();
}
};
Thread thread1 = new Thread(task1, "线程-1");
Thread thread2 = new Thread(task1, "线程-2");
Thread thread3 = new Thread(task2, "线程-3");
thread1.start();
thread2.start();
thread3.start();
}
}

浙公网安备 33010602011771号