首页IT科技aqs获取锁(重大发现,AQS加锁机制竟然跟Synchronized有惊人的相似)

aqs获取锁(重大发现,AQS加锁机制竟然跟Synchronized有惊人的相似)

时间2025-06-15 09:28:14分类IT科技浏览4469
导读:在并发多线程的情况下,为了保证数据安全性,一般我们会对数据进行加锁,通常使用Synchronized或者...

在并发多线程的情况下              ,为了保证数据安全性                     ,一般我们会对数据进行加锁       ,通常使用Synchronized或者ReentrantLock同步锁              。Synchronized是基于JVM实现       ,而ReentrantLock是基于Java代码层面实现的                     ,底层是继承的AQS                     。

AQS全称AbstractQueuedSynchronizer              ,即抽象队列同步器       ,是一种用来构建锁和同步器的框架       。

我们常见的并发锁ReentrantLock              、CountDownLatch                     、Semaphore       、CyclicBarrier都是基于AQS实现的                     ,所以说不懂AQS实现原理的              ,就不能说了解Java锁       。

当我仔细研究AQS底层加锁原理,发现竟然跟Synchronized加锁原理有惊人的相似                     。让我突然想到一句名言                     ,记不清怎么说了                     ,意思是框架底层原理很相似,大家多学习底层原理              。

Synchronized的加锁流程在前几篇文章已经详细讲过              ,没看过一块再温习一下       。

1. Synchronized加锁流程

我们先想一下Synchronized的加锁需求                     ,如果让你设计Synchronized对象锁存储结构       ,该怎么设计?

多个线程执行到Synchronized代码块              ,只有一个线程获取锁                     ,然后执行同步代码块(需要记录哪个线程获取了对象锁)                     。 其他线程被阻塞(被阻塞的线程       ,是不是可以用链表设计个阻塞队列?) 持有锁的线程调用wait方法       ,释放锁                     ,等待被唤醒(等待的线程              ,是不是可以用链表设计个等待队列?)              。 被阻塞的线程开始竞争锁 调用notify方法       ,唤醒等待的线程                     ,被唤醒的线程进入阻塞队列              ,一块竞争锁。

上面描述了Synchronized的加锁流程,Synchronized对象锁存储结构是不是跟咱们想的一样?实际就是的                     。

下面是对象锁的存储数据结构(由C++实现):

ObjectMonitor() { _header = NULL; _count = 0; _waiters = 0, _recursions = 0; _object = NULL; _owner = NULL; // 持有锁的线程 _WaitSet = NULL; // 等待队列                     ,存储处于wait状态的线程 _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; FreeNext = NULL ; _EntryList = NULL ; // 阻塞队列                     ,存储处于等待锁block状态的线程 _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; }

上图展示了对象锁的基本工作机制:

当多个线程同时访问一段同步代码时,首先会进入 _EntryList队列中阻塞                     。

当某个线程获取到对象的对象锁后进入临界区域              ,并把对象锁中的 _owner变量设置为当前线程                     ,即获得对象锁。

若持有对象锁的线程调用 wait() 方法       ,将释放当前持有的对象锁              ,_owner变量恢复为null                     ,同时该线程进入 _WaitSet 集合中等待被唤醒              。

在_WaitSet集合中的线程被唤醒       ,会被再次放到_EntryList队列中       ,重新竞争获取锁                     。

若当前线程执行完毕也将释放对象锁并复位变量的值                     ,以便其他线程进入获取锁       。

Synchronized对象锁存储结构和加锁流程              ,竟然跟咱们想的一样              。

再看一下AQS的存储结构和加锁流程       ,有没有相似的地方                     。

2. AQS加锁原理

先分析一下                     ,我们使用AQS的加锁需求:

多个线程执行到acquire方法的时候              ,只有一个线程获取锁,然后执行同步代码块(需要记录哪个线程获取了对象锁)       。 其他线程被阻塞(被阻塞的线程                     ,是不是可以用链表设计个阻塞队列?名叫              ”同步队列“?) 持有锁的线程调用await方法                     ,释放锁,等待被唤醒(等待的线程              ,是不是可以用链表设计个等待队列?名叫                     ”条件队列“?)       。 被阻塞的线程开始竞争锁 调用signal方法                     ,唤醒等待的线程       ,被唤醒的线程进入阻塞队列              ,一块竞争锁                     。

AQS的需求跟Synchronized一模一样              。

我们再看一下AQS实际的加锁机制是怎么设计的?是不是跟Synchronized相似?

AQS的加锁流程并不复杂                     ,只要理解了同步队列条件队列       ,以及它们之间的数据流转       ,就算彻底理解了AQS       。

当多个线程竞争AQS锁时                     ,如果有个线程获取到锁              ,就把ower线程设置为自己 没有竞争到锁的线程       ,在同步队列中阻塞(同步队列采用双向链表                     ,尾插法)                     。 持有锁的线程调用await方法              ,释放锁,追加到条件队列的末尾(条件队列采用单链表                     ,尾插法)              。 持有锁的线程调用signal方法                     ,唤醒条件队列的头节点,并转移到同步队列的末尾。 同步队列的头节点优先获取到锁

可以看到AQSSynchronized的加锁流程几乎是一模一样的              ,AQS中同步队列就是SynchronizedEntryList                     ,AQS中条件队列就是Synchronized中的waitSet       ,两个队列之间的数据转移流程也是一样的                     。

3. 总结

AQSSynchronized的加锁流程是一样的              ,都是通过同步队列和条件队列实现的                     ,阻塞状态的线程被放到同步队列中       ,等待状态的线程被放到条件队列中       ,从条件队列唤醒的线程又被转移到同步队列末尾                     ,一块竞争锁                     。

看完AQS加锁流程              ,还没有人不懂AQS的?

下篇文章再讲一下AQS加锁具体的源码实现。里面有很多精巧的设计       ,值得我们学习              。

比如:

为什么同步队列要设计成双向链表?而条件队列要设计成单链表?

为什么AQS加锁性能这么好(乐观锁CAS使用)?

同步队列和条件队列中节点怎么用一个对象实现?

释放锁后                     ,怎么唤醒同步队列中线程?

我是「一灯架构」              ,如果本文对你有帮助,欢迎各位小伙伴点赞       、评论和关注                     ,感谢各位老铁                     ,我们下期见

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
苹果cms采集设置(苹果CMSv10采集教程-打造高效网站内容收集利器) 百度如何提升关键词排行(如何提升网站在百度的关键词排名)