博客
关于我
ReentrantLock源码分析
阅读量:772 次
发布时间:2019-03-23

本文共 3364 字,大约阅读时间需要 11 分钟。

ReentrantLock和AQS技术深入解析

ReentrantLock是Java Concurrent包中提供的一种可重入锁,主要用于实现多线程环境下的资源同步。可重入锁的意义在于允许持有锁的一线程多次获取锁资源,而无需每次都释放锁,这避免了死锁的发生,极大提升了多线程应用的性能和可靠性。

AQS(AbstractQueuedSynchronizer)简介

ReentrantLock的实现基础是AQS,一个抽象的同步队列器,用于实现两种同步模式:排他(独占)模式和共享模式。排他模式下,AQS提供了可重入锁的实现机制,而共享模式适用于线程之间可以并发访问的场景。

AQS的核心结构包括一个状态变量state、持有锁的线程Thread exclusiveOwnerThread,以及一个双端队列用于管理等待锁的线程。

核心变量分析

  • state:用于表示锁的状态,值为0时无持有者,非0时表示有持有者。可重入锁情况下,state会递增,表示同一线程多次获取锁资源。
  • exclusiveOwnerThread:记录当前持有锁的线程,初始值为null。

等待队列管理

AQS使用双端队列实现等待队列,头尾节点通过Node对象表示。每个节点包含:

  • waitStatus:等待状态,初始值为0。可能状态包括:

    • SIGNAL(-1):指示当前节点需要唤醒。
    • CANCELLED(1):当前线程已取消排队。
  • Thread thread:对应等待的线程。

节点的插入和移除通过自旋锁实现,以确保在高并发情况下操作的原子性。

ReentrantLock实现细节

ReentrantLock本身通过内部类Sync(继承自AQS)实现,可分为公平锁和非公平锁两种类型。

  • 非公平锁:在获取锁时不考虑等待队列,直接抢占锁或进入队列。
  • 公平锁:先检查等待队列头部是否有其他线程(FIFO),再进行锁获取。

锁的获取过程(详解)

非公平锁(NonfairSync)

非公平锁的lock()方法:

public final void lock() {    if (compareAndSetState(0, 1)) {        setExclusiveOwnerThread(Thread.currentThread());    } else {        acquire(1);    }}public final void acquire(int arg) {    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))        selfInterrupt();}
  • tryAcquire:尝试通过compareAndSet获取锁,成功则更新exclusiveOwnerThread;失败则加入等待队列。
  • acquireQueued:将线程挂入队列,并阻塞直到唤醒或中断。

公平锁(FairSync)

public final void lock() {    acquire(1);}public final boolean tryAcquire(int acquires) {    if (getQueue().hasQueuedPredecessors()) {        if (compareAndSetState(0, acquires)) {            setExclusiveOwnerThread(Thread.currentThread());            return true;        }    }    return false;}
  • tryAcquire:先检查等待队列是否有前驱节点,若有则需要排队,否则直接获取锁。

锁的释放(unlock()方法)

public void unlock() {    sync.release(1);}public boolean release(int arg) {    if (tryRelease(arg)) {        unparkSuccessor(head);        return true;    }    return false;}protected final boolean tryRelease(int releases) {    if (Thread.currentThread() != getExclusiveOwnerThread())        throw new IllegalMonitorStateException();    int c = getState() - releases;    if (c == 0) {        setExclusiveOwnerThread(null);        setState(c);        return true;    }    setState(c);    return true;}
  • release:尝试释放锁,唤醒等待队列的头节点。

中断处理(lockInterruptibly()方法)

public void lockInterruptibly() throws InterruptedException {    sync.acquireInterruptibly(1);}public final void acquireInterruptibly(int arg) throws InterruptedException {    if (Thread.interrupted())        throw new InterruptedException();    if (!tryAcquire(arg))        doAcquireInterruptibly(arg);}private void doAcquireInterruptibly(int arg) throws InterruptedException {    final Node node = addWaiter(Node.EXCLUSIVE);    boolean failed = true;    try {        for (;;) {            if (node.predecessor() == head && tryAcquire(arg)) {                setHead(node);                failed = false;                return;            }            if (shouldParkAfterFailedAcquire(node.predecessor(), node) &&                parkAndCheckInterrupt())                throw new InterruptedException();        }    } finally {        if (failed)            cancelAcquire(node);    }}
  • doAcquireInterruptibly:处理中断情况,挂起线程并在收到中断时重置中断标记。

总结

ReentrantLock通过AQS实现了高效的可重入锁机制,在多线程环境中提供了强大的同步能力。其设计巧妙地平衡了并发性能和正确性,适用于广泛的多线程场景。理解AQS内部工作原理是掌握ReentrantLock关键的前提,以便优化应用性能并避免潜在的死锁问题。

AQS的核心在于通过等待队列管理线程同步,支持多种同步模式的实现。非公平锁通过自旋锁实现快速入队,适合并发率高但并发竞争宽松的场景;而公平锁则确保等待线程按FIFO顺序获取锁,适合更严格的公平要求。ReentrantLock的设计为多线程开发提供了可靠的基础,值得深入研究和应用。

转载地址:http://czhzk.baihongyu.com/

你可能感兴趣的文章
Webpack 之 basic chunk graph
查看>>
Mysql5.7版本单机版my.cnf配置文件
查看>>
mysql5.7的安装和Navicat的安装
查看>>
mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
查看>>
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>
Mysql8在Windows上离线安装时忘记root密码
查看>>
MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
查看>>
mysql8的安装与卸载
查看>>
MySQL8,体验不一样的安装方式!
查看>>
MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
查看>>