商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Java并发锁ReentrantLock的实现

Java并发锁ReentrantLock的实现

  发布于2026-07-14 阅读(0)

扫一扫,手机访问

全路径名:ja va.util.concurrent.locks.ReentrantLock,类定义如下:

Ja va并发锁ReentrantLock的实现

/**
 * @since 1.5
 */
public class ReentrantLock implements Lock, ja va.io.Serializable {
    ...
}

ReentrantLock 实现了 Lock 接口,从 JDK1.5 开始引入。这个类大家平时用得不少,但真正理解其内部机制的,恐怕不多。

使用上,ReentrantLock 提供了两种锁机制:公平锁和非公平锁。默认的无参构造方法 ReentrantLock() 创建的是非公平锁;如果想用公平锁,可以通过有参构造 ReentrantLock(boolean fair) 来选择。具体实现靠的是两个内部类:FairSyncNonfairSync,它们都是抽象内部类 Sync 的子类,而 Sync 又继承了 AbstractQueuedSynchronizer。源码如下:

public class ReentrantLock implements Lock, ja va.io.Serializable {
    ...
    private final Sync sync;
    ...
    abstract static class Sync extends AbstractQueuedSynchronizer {...}
    static final class NonfairSync extends Sync {...}
    static final class FairSync extends Sync {...}
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    public void lock() {
        sync.lock();
    }
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    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);
    }
    public Condition newCondition() {
        return sync.newCondition();
    }
    ...
}

Lock 接口定义了5个方法,源码如下:

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

接下来,我们通过 Lock 接口的 lock() 方法实现,来看看 ReentrantLock 是如何实现公平锁的。先讲思路再看代码,会容易得多。

要公平,就得有先来后到。打个比方,就像超市购物结账:如果结账时恰好没人,那就直接结账——拿到锁;如果已经有人在排队,那就排到队伍后面,等轮到你的时候才能结账——拿到锁。很直观,对吧?

ReentrantLock 的内部类 FairSync 负责实现公平锁机制。它继承了 Sync,而 Sync 又继承了 AbstractQueuedSynchronizer。下面是 lock() 相关源码:

static final class FairSync extends Sync {

    final void lock() {
            acquire(1);
    }

    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 abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements ja va.io.Serializable {
    ...
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    ...
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
    ...
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) 
                        && parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
}

FairSync 的 lock() 方法直接调用 AbstractQueuedSynchronizeracquire() 去获取锁。在 acquire() 中,先通过 FairSynctryAcquire() 处理“没人排队”的场景:

  • int c = getState():获取 AbstractQueuedSynchronizer 的状态值。c = 0 表示目前没有线程持有锁。
  • !hasQueuedPredecessors():判断是否有其他线程在排队,如果没有,才能直接尝试获取。
  • compareAndSetState(0, acquires):通过 CAS(Compare and Swap)这个 CPU 硬件原语来原子地获取锁。
  • setExclusiveOwnerThread(current):成功获取锁后,将当前线程绑定为独占所有者。
  • else if (current == getExclusiveOwnerThread()):如果锁已经被当前线程持有,那就把状态 c 加 1。这正是 ReentrantLock 可重入性的体现——同一个线程在未释放锁时可以重复加锁,每次状态加 1。

如果没人排队但抢锁失败(比如 CAS 被其他线程抢先),那就进入排队场景。acquire() 方法的后续逻辑:

  • for (;;):无限循环,直到获取锁。
  • if (p == head && tryAcquire(arg)):只有排在队列首位的线程才有资格竞争锁。这里的 p 就是当前节点的前驱节点(理论上应该是 head)。
  • parkAndCheckInterrupt():如果没抢到,线程就会被阻塞,这里不做深入讨论。

搞懂了公平锁,非公平锁就简单多了。非公平锁由 NonfairSync 实现:

static final class NonfairSync extends Sync {
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
    }
}
abstract static class Sync extends AbstractQueuedSynchronizer {
    ...
    final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
    }
    ...
}

从源码可以清晰看到:上来就直接调用 compareAndSetState(0, 1) 抢锁,根本不管有没有人在排队。这就是非公平锁的核心——谁抢到算谁的,不讲先来后到。

本文转载于:https://www.jb51.net/program/362722ifw.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注