在并发多线程的情况下,为了保证数据安全性,一般我们会对数据进行加锁,通常使用Synchronized或者ReentrantLock同步锁。Synchronized是基于JVM实现,而ReentrantLock是基于Java代码层面实现的,底层是继承的AQS。
AQS全称AbstractQueuedSynchronizer,即抽象队列同步器,是一种用来构建锁和同步器的框架。
我们常见的并发锁ReentrantLock、CountDownLatch、Semaphore、CyclicBarrier都是基于AQS实现的,所以说不懂AQS实现原理的,就不能说了解Java锁。
当我仔细研究AQS底层加锁原理,发现竟然跟Synchronized加锁原理有惊人的相似。让我突然想到一句名言,记不清怎么说了,意思是框架底层原理很相似,大家多学习底层原理。
Synchronized的加锁流程在前几篇文章已经详细讲过,没看过一块再温习一下。
我们先想一下Synchronized的加锁需求,如果让你设计Synchronized的对象锁存储结构,该怎么设计?
上面描述了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的存储结构和加锁流程,有没有相似的地方。
先分析一下,我们使用AQS的加锁需求:
AQS的需求跟Synchronized一模一样。
我们再看一下AQS实际的加锁机制是怎么设计的?是不是跟Synchronized相似?

AQS的加锁流程并不复杂,只要理解了同步队列和条件队列,以及它们之间的数据流转,就算彻底理解了AQS。
可以看到AQS和Synchronized的加锁流程几乎是一模一样的,AQS中同步队列就是Synchronized中EntryList,AQS中条件队列就是Synchronized中的waitSet,两个队列之间的数据转移流程也是一样的。
AQS跟Synchronized的加锁流程是一样的,都是通过同步队列和条件队列实现的,阻塞状态的线程被放到同步队列中,等待状态的线程被放到条件队列中,从条件队列唤醒的线程又被转移到同步队列末尾,一块竞争锁。
看完AQS加锁流程,还没有人不懂AQS的?
下篇文章再讲一下AQS加锁具体的源码实现。里面有很多精巧的设计,值得我们学习。
比如:
为什么同步队列要设计成双向链表?而条件队列要设计成单链表?
为什么AQS加锁性能这么好(乐观锁CAS使用)?
同步队列和条件队列中节点怎么用一个对象实现?
释放锁后,怎么唤醒同步队列中线程?
我是「一灯架构」,如果本文对你有帮助,欢迎各位小伙伴点赞、评论和关注,感谢各位老铁,我们下期见

我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night
关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭9年前。Improvethisquestion我现在是java专业人士,我喜欢使用ruby。这两种语言有什么相似之处吗?主要区别是什么?因为两者都是面向对象的。
在我们的项目中,我们有一些“被遗忘的”类存在了很长一段时间。那些类已被其他类替代,但我们忘记删除它们。是否有一些自动化的方法/工具可以发现Ruby{onRails}应用程序中没有使用哪些类?谢谢! 最佳答案 这个问题已经被提出了很多次,但是最好的答案都在这里:FindunusedcodeinaRailsapp我个人喜欢日志解析:https://stackoverflow.com/a/14161807但在任何情况下,您都可以创建自己的记录器,扩展ActiveRecord::Base以创建一个观察器,该观察器将最常用的模块存储在数据库中
我在用Ruby元编程开玩笑,我写了这段代码:classClassdef===(other)other.kind_of?(self)endendclassFakeClassdefinitialize(object)methods.each{|m|eval"undef#{m}"ifm.to_sym!=:methods}define=procdo|m|eval(这会创建一个模拟对象的假类。看:a=FakeClass.new(1)#=>1a.class#=>Fixnuma.methods#=>ReturnallFixnummethodsa+1#=>2(isnotaFakeClass)Fixnu
我有一个字符串数组,数量不多(可能几百个)但通常很长(几百个字符)。这些字符串通常是无意义的,并且彼此不同。但是在一组这样的字符串中,可能300个中有5个具有很大的相似性。事实上,它们是相同的字符串,不同的是格式、标点符号和一些单词..我怎样才能算出那组字符串?顺便说一句,我正在用ruby编写,但如果没有别的,伪代码算法就可以了。谢谢 最佳答案 假设您不担心每个单词的拼写错误或其他错误,您可以执行以下操作:构建一个倒排索引,它基本上是一个以单词为键的散列,指向包含该单词的字符串的指针列表(如何处理重复出现由您决定)。要确定与给定
2022年10月21日星期五【数据指标】加密货币总市值:$0.95万亿BTC市值占比:38.51%恐慌贪婪指数:23极度恐慌 【今日快讯】1、【政讯】1.1.1、美联储布拉德:市场预期美联储11月会加息75个基点1.1.2、美联储哈克:将维持加息一段时间1.2、美国10年期国债收益率触及4.197%,为2008年6月以来最高1.3、法国数字转型部长:政府将专注于DeFi和Web31.4、巴西ATM机将于11月3日起支持USDT1.5、美众议院副议长将于11月初加入a16zCrypto担任政府事务主管1.6、香港数字资产托管机构FirstDigitalTrust首席执行官:香港仍是安全
我正在使用Ruby-Tk为OSX开发一个桌面应用程序,我想为该应用程序提供一个AppleEvents接口(interface)。这意味着应用程序将定义它将响应的AppleScript命令的字典(对应于发送到应用程序的Apple事件),并且用户/其他应用程序可以使用AppleScript命令编写Ruby-Tk应用程序的脚本。其他脚本语言支持此类功能——Python通过位于http://appscript.svn.sourceforge.net/viewvc/appscript/py-aemreceive/的py-aemreceive库和Tcl通过位于http://tclae.source
简而言之,我的原始代码(用Ruby编写)如下所示:#$seenisahashtomemoizepreviouslyseensets#$sparseisahashofusernamestoalistofneighboringusernames#$setisthelistofoutputclusters$seen={}defsubgraph(set,adj)hash=(set+adj).sortreturnif$seen[hash]$sets.pushset.sort.join(",")ifadj.empty?andset.size>2adj.each{|node|subgraph(set
Method#unbind返回对该方法的UnboundMethod引用,稍后可以使用UnboundMethod#bind将其绑定(bind)到另一个对象.classFooattr_reader:bazdefinitialize(baz)@baz=bazendendclassBardefinitialize(baz)@baz=bazendendf=Foo.new(:test1)g=Foo.new(:test2)h=Bar.new(:test3)f.method(:baz).unbind.bind(g).call#=>:test2f.method(:baz).unbind.bind(h).
我正在尝试使用以下查询从我的数据库中检索多条记录:User.where('nameilike?','%thomas%')这很好用。现在我想同时检索多条记录并尝试了这个(这在语法上似乎是不正确的):User.where('nameilikeany',['%thomas%','%james%','%martin%'])我做错了什么?所以澄清一下:我想检索与其中一个名称匹配的所有记录,所以它是我正在寻找的OR语句。 最佳答案 你可以这样做User.where('nameilikeany(array[?])',['%thomas%','%j