自己太笨了,总感觉有点绕,就整理下吧~

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方法的理解相关推荐

  1. python threading模块的方法_Python THREADING模块中的JOIN()方法深入理解

    看了oschina上的两个代码,受益匪浅.其中对join()方法不理解,看python官网文档的介绍: join([timeout]):等待直到进程结束.这将阻塞正在调用的线程,直到被调用join() ...

  2. 关于numy中np.expand_dims方法的理解?

    转自知乎 锴锴 烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫 150 人赞同了该回答 这个东西的主要作用,就是增加一个维度. 现在我们假设有一个数组A,数组A是一个两行三列的矩阵.大小我们记成(2,3). 先明白 ...

  3. matlab中的并行方法与理解(2):parfor中的变量类型

    转载至:http://blog.csdn.net/caozhk/article/details/38234293?utm_source=tuicool&utm_medium=referral ...

  4. css中的setProperty()方法的理解

    1.调用它需要js对象,不能是jquery对象 $("body")[0].style.setProperty("--xx",$("img") ...

  5. 【java并发】AQS中acquire方法解析

    AQS,全名AbstractQueuedSynchronizer(抽象队列同步器),它是CLH(不明白的可以先了解一下CLH)的变种.它与CLH不同之处在于:        CLH是一种公平锁,它是通 ...

  6. 关于AQS中enq( )方法CAS操作的疑惑

    private Node enq(final Node node) {for (;;) {Node t = tail;//如果队列为空则新建头结点if (t == null) { // Must in ...

  7. AQS理解之七——AQS中的条件队列

    AQS中的条件队列 在AQS中还实现了一个类,ConditionObject,它实现了Condition接口,实现一个绑定在锁上的条件队列. 先看看他的uml图. 主要方法 它实现了Condition ...

  8. Java中关于Arrays.sort的两种重载方法的理解

    前言 在java中重载排序方法的方法目前有两种,一种是实现Comparable接口的compareTo方法,还有一种是用比较器(comparator) 作为参数,其中比较器是实现了Comparator ...

  9. sklearn中GBDT的一些参数、属性、方法的理解

    文章目录 GBDT 分类器 引入 重要参数 loss learning_rate subsample n_estimators criterion max_depth min_samples_leaf ...

最新文章

  1. 如何解决现有的问题——VBA课程第五次讨论2007年12月13日
  2. Struts_改写客户列表练习
  3. 估价范围还没有生产式的物料帐薄
  4. js调用php和php调用js的方法举例
  5. _Linux软件安装
  6. java 中的流_Java中的流(IO
  7. 为Cubieboard打造完美Debian系统
  8. 源码大招:不服来战!撸这些完整项目,你不牛逼都难!
  9. 互联网原理和html基础,计算机网络基础知识习题及答案(八)
  10. idea—开启Run DashBoard
  11. 如何在Ubuntu 14.10 上安装WordPress?
  12. L1-040 最佳情侣身高差-PAT团体程序设计天梯赛GPLT
  13. 练手级计算机,快来打怪
  14. Java学习笔记【2】:抛出异常
  15. python log日志常用用法总结
  16. 2022最新 wifi大师小程序独立版3.0.8
  17. excel锁定单元格不能修改_Excel如何保护特定的数据不被更改?
  18. 深度解析dubbo源码系列
  19. 设计技巧之:LOGO色彩搭配
  20. JAVA 生成同音字的方法,随机生成汉字,汉字转拼音,写的不好,望指正.谢谢~

热门文章

  1. html分享到微信朋友圈代码,微信分享给朋友及朋友圈JS代码
  2. 13.3断流_更新13.3.1后,用WiFi王者荣耀断流,时不时460.飞在天上的解决办法。
  3. Ping一个IP地址是否有效
  4. 使用系统导航栏,设置成全透明的方法
  5. GSM蜂窝移动通信系统 --- 时间色散和均衡
  6. linux查看磁盘占用情况
  7. 2017年的端午节祝福语
  8. 正态分布检验:检验序列数据是否符合正态分布
  9. AR剪辑笔记之视频调色
  10. 限制输入框 输入文本类型(纯数字/数字/中文/英文)