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

 
private Node enq(final Node node) {

for (;;) {

Node t = tail;

//如果队列为空则新建头结点

if (t == null) { // Must initialize

if (compareAndSetHead(new Node()))//这个操作是新建队列 

//将tail指向头结点

tail = head;

} else {

//1.将新节点的前置指针指向链表尾部

node.prev = t;

//2.通过CAS将tail的引用指向node

//这里的设计很厉害,总体来说先tail 指向本节点 ,如果其他线程进来也不影响
//t局部变量是为了暂时保存前节点,compareAndSetTail(t,node) 这个操作只是做了tail 指向新节点;如//果本县城做完了compareAndSetTail(t,node) 此时有个线程进来了,并且要操作队列,那他直接操作
tail就可以了,等本新线程继续执行了,他继续操作本线程的前节点指向本线程的当前节点。
if (compareAndSetTail(t, node)) {//只是让tail 指向了 新节点

//3.将原尾部节点的后置指针指向新节点

t.next = node;//所以这里前节点需要指向后节点


//for循环的出口

return t;

}

}

}

}


 

这是节点进入同步队列的方法,其中的CAS操作compareAndSetTail(t, node),作用为将tail的引用指向node,参数t中的内容是tail的旧引用对象地址,node是新节点的地址。再来看看AQS中compareAndSetTail(t, node)具体内容,

 
  1. private final boolean compareAndSetTail(Node expect, Node update) {

  2. return unsafe.compareAndSwapObject(this, tailOffset, expect, update);

  3. }

 
  1. tailOffset = unsafe.objectFieldOffset

  2. (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));

这里的tailOffset,是通过unsafe类中的方法获取到的是“tail”变量相对于Java对象的“起始地址”的偏移量,即tailOffset可以理解为tail的地址。也就是说这里CAS操作更新的知识tail变量的地址上的数据,并不会对局部变量t上的值做修改,执行完compareAndSetTail(t, node)后,t还是指向原来的旧链尾,而tail指向了新的节点。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值