AQS入队操作的问题
AQS入队操作为什么先设置prev的值,再cas设置tail的值?纠结这个问题是看unparkSuccessor()方法为什么从尾节点开始遍历的原因有入队操作可能会导致next为空,回过头看enq()方法,没有搞明白这里的顺序,为什么不直接CAS替换tail成功之后再设置prev的值。请教下各位,红框中的部分放到if块中会有什么问题?
回答:
- 如果放在的if 里面,当
tail
设置成功后的瞬间,它虽然是tail
,但还是一个孤儿。如果在 成功后,node.pred = oldtail
之前tail
(此时是node) 已经被其他线程使用了呢?比如unparkSuccessor
,此时肯定会造成错误的状态。如果严格来说,在指针被推移的时候tail
就应该是完整的tail
了。也就是完全同步tail
和node
之间的关联,但这样显然效率不高。所以优先prev
, - 为什么不把
oldtail.next = node
也放在外面呢?oldtail
在tail
(指引用) 被修改之前可能会被使用,如果在oldtail.next = node
之后,tail = node
之前,此时它(tail 即 oldtail
)存在next
可能导致判断失误。 - 虽然在
tail = node
的成功的之后,在oldtail.next = node
之前,它(tail 即 node
)的next
马上被使用了不是也会出错吗? 这里是做了逻辑的上的处理,即使next
为空 ,也不一定就说明此节点是尾节点(next
的注释),他会从tail
开始向前遍历,这就正常了,应为prev
是存在的。
要想写好多线程 ,特别是用cas 来同步,真的挺难,需要考虑的问题呈几何倍数增加,对于普通的程序还是用锁实在点,比如这段代码,只要直接加个锁,也就不需要考虑这些什么前,什么后的了。
回答:
如果把这个代码移到if里面,假设a,b两个线程同时走到这里来,a线程cas抢占成功,然后进入if里面的代码,a线程会将node连到队尾,b线程此时cas竞争失败,直接走到enq方法,此时b线程构造的node就变成一个孤点了,他就永远无法加入到aqs的队列了
以上是 AQS入队操作的问题 的全部内容, 来源链接: utcz.com/p/944539.html