返回

剖析ReentrantLock,深入了解可重入锁的源码精髓

后端

可重入锁ReentrantLock简介

在Java并发编程领域,ReentrantLock无疑是一款耀眼明星,自JDK1.5引入以来,便以其强大的功能和灵活的应用场景,赢得了开发者的广泛青睐。与synchronized相比,ReentrantLock提供了更加细粒度的控制,让开发者能够更加精准地管理线程同步,避免不必要的资源竞争。

ReentrantLock的工作原理

ReentrantLock的运作机制并不复杂,但要深入理解其精髓,需要我们从底层源码入手。ReentrantLock的核心数据结构是一个叫做“state”的int变量,它记录了锁的当前状态,取值为0表示锁未被持有,取值大于0表示锁已被持有,其值即为持有锁的线程数量。当一个线程试图获取锁时,它会调用ReentrantLock的lock()方法,如果state为0,则表示锁未被持有,该线程可以成功获取锁,并将state加1,表示锁已被自己持有。如果state不为0,则表示锁已被其他线程持有,该线程需要等待锁释放,直到state变为0,才能成功获取锁。

ReentrantLock还提供了一个tryLock()方法,该方法尝试获取锁,但不会阻塞当前线程。如果锁已被持有,tryLock()方法将立即返回false,表示获取锁失败。

ReentrantLock的优势

  • 可重入性: ReentrantLock支持可重入,这意味着同一个线程可以多次获取同一把锁,而不会发生死锁。这是ReentrantLock区别于synchronized的一大优势。
  • 公平性: ReentrantLock可以设置为公平锁或非公平锁。公平锁保证了线程获取锁的顺序与它们请求锁的顺序一致,而非公平锁则不提供这样的保证。公平锁可以避免某些情况下饥饿现象的发生,但也会带来一定的性能开销。
  • 可中断性: ReentrantLock支持中断,这意味着当一个线程在等待锁时,可以被其他线程中断。这使得ReentrantLock在某些场景下更加灵活。

ReentrantLock的使用场景

ReentrantLock的应用场景非常广泛,特别适合于以下场景:

  • 需要对共享资源进行细粒度控制的场景。
  • 需要避免死锁的场景。
  • 需要公平锁来保证线程获取锁的顺序的场景。
  • 需要可中断锁来处理某些特殊情况的场景。

ReentrantLock的源码分析

深入剖析ReentrantLock的源码,我们可以一窥Java并发编程的奥秘。ReentrantLock的源码位于java.util.concurrent.locks包中,核心类是ReentrantLock类。该类包含了许多方法,用于管理锁的状态、获取锁、释放锁等操作。

public class ReentrantLock implements Lock, java.io.Serializable {

    private final Sync sync;

    abstract static class Sync extends AbstractQueuedSynchronizer {
        abstract void lock();
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    static final class NonfairSync extends Sync {
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
    }

    static final class FairSync extends Sync {
        final void lock() {
            acquire(1);
        }
    }

    public ReentrantLock() {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    public void lock() {
        sync.lock();
    }

    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    public void unlock() {
        sync.release(1);
    }

    public Condition newCondition() {
        return sync.newCondition();
    }

    public int getHoldCount() {
        return sync.getHoldCount();
    }

    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }

    public boolean isLocked() {
        return sync.isLocked();
    }

    public final boolean isFair() {
        return sync instanceof FairSync;
    }
}

从这段源码中,我们可以看到ReentrantLock是如何实现可重入锁、公平锁等特性的。

结语

ReentrantLock是Java并发编程中的一款重要工具,它提供了强大的功能和灵活的应用场景。通过深入理解ReentrantLock的原理和源码,我们可以更好地掌握Java并发编程的精髓,编写出更加可靠、高效的并发程序。