关于AQS中的enq方法的理解
自己太笨了,总感觉有点绕,就整理下吧~
private Node enq(final Node node) {//自旋锁for (;;) {//tail默认就是nullNode t = tail;if (t == null) { // Must initialize//因为tail默认是null,所以首次一定会进来//compareAndSetHead在下面//也就是首次一定会把一个新的node设置为headif (compareAndSetHead(new Node()))//tail=head=new Node()tail = head;//到这里就是tail和head都会指向new Node} else {//第二次一定进入else发//假如此时进入了一个线程A,这个A已经被封装成了node传进来//当前的node的pre指向t,也就是tail,也就是刚才创建的Node,//因为第一行就定义了Node t = tail,而t=head=nodenode.prev = t;//这里看下面的compareAndSetTail方法//把tail节点赋值为新传入的node(Thread A),赋值操作就相当于指向if (compareAndSetTail(t, node)) {//这里的t指的是原来的tail节点,tail指向一开始的new Node//所以就是new Node的next指向新传入的node(Thread A)t.next = node;return t;}}}
}private final boolean compareAndSetHead(Node update) {//当前的head字段,和null值比对,默认是null,所以相等,所以赋值为update,也就是new node()return unsafe.compareAndSwapObject(this, headOffset, null, update);
}private final boolean compareAndSetTail(Node expect, Node update) {//当前的tail字段和期望值exepct,即t进行比较,一定是相等的啊,以为t=tail么,所以更新赋值为update,//即新传进来的node(Thread A)return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
第一次一定是进入if
当有新的线程进入的时候,进入else(其实没有新的线程进入还是要进入else的),红色的是else所做的操作
总结:
这里面head和tail都是一个node,但是这里我理解为一个类似于指针的东西,它们存在的意义也是为了维持这个双向的链表,没有实际的意义,包括prev和next也是。
还是挺绕的,感觉没必要理解这么透彻,主要思想就是
第一次进来的时候创建这个双向链表的空节点,后面传入新的节点的时候,开始往双向链表后面添加新的节点,而head和tail永远指向第一个和最后一个,中间都是一些切换指针(我这里暂且理解为指针吧,也就是赋值操作,比如tail和head的赋值,prev和next的赋值。)
for(;;)是一个自旋锁,为了不停的去尝试添加节点,但是可能存在并发问题,所以通过cas的方式,添加,可能上次被线程a抢占先机,这次自己还是要去尝试,如何进行不断的尝试?所以通过自旋锁解决,当然如果添加成果最后会通过return跳出自旋锁。
个人认为这个自旋锁和cas的操作用的很厉害,值得学习!
仔细想想为什么这么设计?
因为当前的这个compareAndSetTail和compareAndSetHead,这两个操作,简单说就是为了切换指针指向,简单说就是一“操作”,任何操作,因为在操作系统中,虽然我们目前在解决并发问题,但是也是存在并发问题的,对于这个“操作来说”。所以我们可以选择加锁,也可以选择这种cas自旋锁的方式,因为这个操作可能是很快的,因为可能同时又一万个线程都被阻塞了(极端一点的情况),这个时候,会有很多的切换指针的这个“操作”,反复的加悲观锁的话,没有cas这种乐观锁好。简单总结下,就是这种cas自旋锁的方式能提升性能。
以上全是我的个人理解,可能存在很大的问题,希望没有误导到你,如果有问题还希望您及时指出。
关于AQS中的enq方法的理解相关推荐
- python threading模块的方法_Python THREADING模块中的JOIN()方法深入理解
看了oschina上的两个代码,受益匪浅.其中对join()方法不理解,看python官网文档的介绍: join([timeout]):等待直到进程结束.这将阻塞正在调用的线程,直到被调用join() ...
- 关于numy中np.expand_dims方法的理解?
转自知乎 锴锴 烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫 150 人赞同了该回答 这个东西的主要作用,就是增加一个维度. 现在我们假设有一个数组A,数组A是一个两行三列的矩阵.大小我们记成(2,3). 先明白 ...
- matlab中的并行方法与理解(2):parfor中的变量类型
转载至:http://blog.csdn.net/caozhk/article/details/38234293?utm_source=tuicool&utm_medium=referral ...
- css中的setProperty()方法的理解
1.调用它需要js对象,不能是jquery对象 $("body")[0].style.setProperty("--xx",$("img") ...
- 【java并发】AQS中acquire方法解析
AQS,全名AbstractQueuedSynchronizer(抽象队列同步器),它是CLH(不明白的可以先了解一下CLH)的变种.它与CLH不同之处在于: CLH是一种公平锁,它是通 ...
- 关于AQS中enq( )方法CAS操作的疑惑
private Node enq(final Node node) {for (;;) {Node t = tail;//如果队列为空则新建头结点if (t == null) { // Must in ...
- AQS理解之七——AQS中的条件队列
AQS中的条件队列 在AQS中还实现了一个类,ConditionObject,它实现了Condition接口,实现一个绑定在锁上的条件队列. 先看看他的uml图. 主要方法 它实现了Condition ...
- Java中关于Arrays.sort的两种重载方法的理解
前言 在java中重载排序方法的方法目前有两种,一种是实现Comparable接口的compareTo方法,还有一种是用比较器(comparator) 作为参数,其中比较器是实现了Comparator ...
- sklearn中GBDT的一些参数、属性、方法的理解
文章目录 GBDT 分类器 引入 重要参数 loss learning_rate subsample n_estimators criterion max_depth min_samples_leaf ...
最新文章
- 如何解决现有的问题——VBA课程第五次讨论2007年12月13日
- Struts_改写客户列表练习
- 估价范围还没有生产式的物料帐薄
- js调用php和php调用js的方法举例
- _Linux软件安装
- java 中的流_Java中的流(IO
- 为Cubieboard打造完美Debian系统
- 源码大招:不服来战!撸这些完整项目,你不牛逼都难!
- 互联网原理和html基础,计算机网络基础知识习题及答案(八)
- idea—开启Run DashBoard
- 如何在Ubuntu 14.10 上安装WordPress?
- L1-040 最佳情侣身高差-PAT团体程序设计天梯赛GPLT
- 练手级计算机,快来打怪
- Java学习笔记【2】:抛出异常
- python log日志常用用法总结
- 2022最新 wifi大师小程序独立版3.0.8
- excel锁定单元格不能修改_Excel如何保护特定的数据不被更改?
- 深度解析dubbo源码系列
- 设计技巧之:LOGO色彩搭配
- JAVA 生成同音字的方法,随机生成汉字,汉字转拼音,写的不好,望指正.谢谢~