博客
关于我
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/

你可能感兴趣的文章
MYSQL:基础——3N范式的表结构设计
查看>>
MYSQL:基础——触发器
查看>>
Mysql:连接报错“closing inbound before receiving peer‘s close_notify”
查看>>
mysqlbinlog报错unknown variable ‘default-character-set=utf8mb4‘
查看>>
mysqldump 参数--lock-tables浅析
查看>>
mysqldump 导出中文乱码
查看>>
mysqldump 导出数据库中每张表的前n条
查看>>
mysqldump: Got error: 1044: Access denied for user ‘xx’@’xx’ to database ‘xx’ when using LOCK TABLES
查看>>
Mysqldump参数大全(参数来源于mysql5.5.19源码)
查看>>
mysqldump备份时忽略某些表
查看>>
mysqldump实现数据备份及灾难恢复
查看>>
mysqldump数据库备份无法进行操作只能查询 --single-transaction
查看>>
mysqldump的一些用法
查看>>
mysqli
查看>>
MySQLIntegrityConstraintViolationException异常处理
查看>>
mysqlreport分析工具详解
查看>>
MySQLSyntaxErrorException: Unknown error 1146和SQLSyntaxErrorException: Unknown error 1146
查看>>
Mysql_Postgresql中_geometry数据操作_st_astext_GeomFromEWKT函数_在java中转换geometry的16进制数据---PostgreSQL工作笔记007
查看>>
mysql_real_connect 参数注意
查看>>
mysql_secure_installation初始化数据库报Access denied
查看>>