CompareAndSwap原子操作原理
Posted scy251147
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CompareAndSwap原子操作原理相关的知识,希望对你有一定的参考价值。
在翻阅AQS(AbstractQueuedSynchronizer)类的过程中,发现其进行原子操作的时候采用的是CAS。涉及的代码如下:
1: private static final Unsafe unsafe = Unsafe.getUnsafe();
2: private static final long stateOffset;
3: private static final long headOffset;
4: private static final long tailOffset;
5: private static final long waitStatusOffset;
6: private static final long nextOffset;
7:
8: static
9: try
10: stateOffset = unsafe.objectFieldOffset
11: (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
12: headOffset = unsafe.objectFieldOffset
13: (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
14: tailOffset = unsafe.objectFieldOffset
15: (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
16: waitStatusOffset = unsafe.objectFieldOffset
17: (Node.class.getDeclaredField("waitStatus"));
18: nextOffset = unsafe.objectFieldOffset
19: (Node.class.getDeclaredField("next"));
20:
21: catch (Exception ex) throw new Error(ex);
22:
23:
24: /**
25: * CAS head field. Used only by enq.
26: */
27: private final boolean compareAndSetHead(Node update)
28: return unsafe.compareAndSwapObject(this, headOffset, null, update);
29:
30:
31: /**
32: * CAS tail field. Used only by enq.
33: */
34: private final boolean compareAndSetTail(Node expect, Node update)
35: return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
36:
37:
38: /**
39: * CAS waitStatus field of a node.
40: */
41: private static final boolean compareAndSetWaitStatus(Node node,
42: int expect,
43: int update)
44: return unsafe.compareAndSwapInt(node, waitStatusOffset,
45: expect, update);
46:
47:
48: /**
49: * CAS next field of a node.
50: */
51: private static final boolean compareAndSetNext(Node node,
52: Node expect,
53: Node update)
54: return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
55:
可以看到用到了compareAndSwapObject和compareAndSwapInt方法,那么究竟是怎么用其来实现原子操作的呢?
我们以compareAndSwapObject方法为例,其源码大致如下:
1: UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
2: UnsafeWrapper("Unsafe_CompareAndSwapObject");
3: oop x = JNIHandles::resolve(x_h); //待更新的新值,也就是UpdateValue
4: oop e = JNIHandles::resolve(e_h); //期望值,也就是ExpectValue
5: oop p = JNIHandles::resolve(obj); //待操作对象
6: HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);//根据操作的对象和其在内存中的offset,计算出内存中具体位置
7: oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);// 如果操作对象中的值和e期望值一致,则更新存储值为x,反之不更新
8: jboolean success = (res == e);
9: if (success) //满足更新条件
10: update_barrier_set((void*)addr, x); // 更新存储值为x
11: return success;
12: UNSAFE_END
从上述源码可以看到,compareAndSwapObject方法中的第一个参数和第二个参数,用于确定待操作对象在内存中的具体位置的,然后取出值和第三个参数进行比较,如果相等,则将内存中的值更新为第四个参数的值,同时返回true,表明原子更新操作完毕。反之则不更新内存中的值,同时返回false,表明原子操作失败。
同样的,compareAndSwapInt方法也是相似的道理,第一个,第二个参数用来确定当前操作对象在内存中的存储值,然后和第三个expect value比较,如果相等,则将内存值更新为第四个updaet value值。
由于原始的方法使用比较麻烦,所以在AQS中进行了封装,大大简化了操作:
1: private static final Unsafe unsafe = Unsafe.getUnsafe();
2: private static final long stateOffset;
3: private static final long headOffset;
4: private static final long tailOffset;
5: private static final long waitStatusOffset;
6: private static final long nextOffset;
7:
8: static
9: try
10: stateOffset = unsafe.objectFieldOffset
11: (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
12: headOffset = unsafe.objectFieldOffset
13: (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
14: tailOffset = unsafe.objectFieldOffset
15: (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
16: waitStatusOffset = unsafe.objectFieldOffset
17: (Node.class.getDeclaredField("waitStatus"));
18: nextOffset = unsafe.objectFieldOffset
19: (Node.class.getDeclaredField("next"));
20:
21: catch (Exception ex) throw new Error(ex);
22:
23:
24: /**
25: * CAS head field. Used only by enq.
26: */
27: private final boolean compareAndSetHead(Node update)
28: return unsafe.compareAndSwapObject(this, headOffset, null, update);
29:
30:
31: /**
32: * CAS tail field. Used only by enq.
33: */
34: private final boolean compareAndSetTail(Node expect, Node update)
35: return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
36:
37:
38: /**
39: * CAS waitStatus field of a node.
40: */
41: private static final boolean compareAndSetWaitStatus(Node node,
42: int expect,
43: int update)
44: return unsafe.compareAndSwapInt(node, waitStatusOffset,
45: expect, update);
46:
47:
48: /**
49: * CAS next field of a node.
50: */
51: private static final boolean compareAndSetNext(Node node,
52: Node expect,
53: Node update)
54: return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
55:
可以在其他项目中作为小模块进行引入并使用。这样使用起来就非常方便了:
1:
2: /**
3: * Creates and enqueues node for current thread and given mode.
4: *
5: * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
6: * @return the new node
7: */
8: private Node addWaiter(Node mode)
9: Node node = new Node(Thread.currentThread(), mode);
10: // Try the fast path of enq; backup to full enq on failure
11: Node pred = tail;
12: if (pred != null)
13: node.prev = pred;
14: if (compareAndSetTail(pred, node))
15: pred.next = node;
16: return node;
17:
18:
19: enq(node);
20: return node;
21:
参考文档:
https://blog.csdn.net/qqqqq1993qqqqq/article/details/75211993
以上是关于CompareAndSwap原子操作原理的主要内容,如果未能解决你的问题,请参考以下文章