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: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
可以看到用到了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
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
从上述源码可以看到,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: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
可以在其他项目中作为小模块进行引入并使用。这样使用起来就非常方便了:
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: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
参考文档:
https://blog.csdn.net/qqqqq1993qqqqq/article/details/75211993
CompareAndSwap原子操作原理的更多相关文章
- Atomic原子操作原理剖析
前言 绝大部分 Objective-C 程序员使用属性时,都不太关注一个特殊的修饰前缀,一般都无脑的使用其非默认缺省的状态,他就是 atomic. @interface PropertyClass @ ...
- Linux Kernel CMPXCHG函数分析
原文地址:http://blog.csdn.net/penngrove/article/details/44175387 最近看到Linux Kernel cmpxchg的代码,对实现很不理解.上网查 ...
- 同步(Synchronization)
多线程应用程序的存在,在运行打开一个潜在的多线程安全的接入资源. 两个线程相同的资源可能会以意想不到的方式改变相互干扰. 例如.一个线程可以覆盖有一个线程改变或使应用程序进入一个潜在的无效的状态未知. ...
- java并发机制锁的类型和实现
synchronized 和 volatile,是最基础的两个锁! volatile是轻量级锁,它在多核处理器开发中保证了共享变量的可见性.即当一个线程修改一个共享变量时,其他线程能够读到这个修改的值 ...
- C++程序员面试题目总结(涉及C++基础、多线程多进程、网络编程、数据结构与算法)
说明:C++程序员面试题目总结(涉及C++基础知识.多线程多进程.TCP/IP网络编程.Linux操作.数据结构与算法) 内容来自作者看过的帖子或者看过的文章,个人整理自互联网,如有侵权,请联系作者 ...
- Java并发之原子变量和原子引用与volatile
我们知道在并发编程中,多个线程共享某个变量或者对象时,必须要进行同步.同步的包含两层作用:1)互斥访问(原子性):2)可见性:也就是多个线程对共享的变量互斥地访问,同时线程对共享变量的修改必须对其他线 ...
- Java 理论与实践: 流行的原子——新原子类是 java.util.concurrent 的隐藏精华(转载)
简介: 在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待.无锁定的算法.在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化.请跟随并 ...
- 《Java并发编程实战》第十五章 原子变量与非堵塞同步机制 读书笔记
一.锁的劣势 锁定后假设未释放.再次请求锁时会造成堵塞.多线程调度通常遇到堵塞会进行上下文切换,造成很多其它的开销. 在挂起与恢复线程等过程中存在着非常大的开销,而且通常存在着较长时间的中断. 锁可能 ...
- Java多线程并发编程之原子变量与非阻塞同步机制
1.非阻塞算法 非阻塞算法属于并发算法,它们可以安全地派生它们的线程,不通过锁定派生,而是通过低级的原子性的硬件原生形式 -- 例如比较和交换.非阻塞算法的设计与实现极为困难,但是它们能够提供更好的吞 ...
随机推荐
- 堆模板(STL版)
题目描述 如题,初始小根堆为空,我们需要支持以下3种操作: 操作1: 1 x 表示将x插入到堆中 操作2: 2 输出该小根堆内的最小数 操作3: 3 删除该小根堆内的最小数 输入输出格式 输入格式: ...
- master节点的部署介绍和前置工作
目录 组件介绍 组件介绍 kubernetes master节点运行组件如下: kube-apiserver.kube-scheduler.kube-controller-manager.kube-n ...
- 少用float浮动?
在css中,float 属性定义元素在哪个方向浮动.也是我在css样式中常用到的属性,后来浏览了一些公司项目代码,发现float属性极少有人使用.随后做了一些调查和研究: 1.在ie6以下,float ...
- 使用ModelArts自动学习完成猫狗声音分类
准备数据 点击下载猫狗声音数据集至本地: 解压,文件包结构大概如下图所示 data ├── test │ ├── cats │ │ ├── cat_20.wav │ │ ├── ...... │ │ ...
- 配置基于接口地址池的DHCP
配置基于接口地址池的DHCP 原理概述 DHCP(动态主机配置协议),采用C/S方式工作,C向S动态请求配置信息,S自动分配配置信息. 基于接口地址池的DHCP服务器,链接这个接口网段的用户都可以从该 ...
- 洛谷 P3420 [POI2005]SKA-Piggy Banks 题解
蒟蒻的第二篇题解 嗯,直接进入正题 先告诉你们这是并查集,好吧,标签上面有,再来分析这为什么是并查集. 根据题意: 每一个存钱罐能够用相应的钥匙打开或者被砸开,Byteazar已经将钥匙放入到一些存钱 ...
- SpringBoot-配置文件相关(五)
SpringBoot-配置文件 SpringBoot官方文档 配置相关 SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的 application.properties 语法结构 : ...
- 基于webpack实现多html页面开发框架八 html引入图片打包和公共页面模块复用
一.解决什么问题 1.html中img引入的图片地址没有被替换,找不到图片 2.html公共部分复用问题,如头部.底部.浮动层等 二.html中img引入图片问题解决 1.在index.html插入i ...
- HDU-1274
在纺织CAD系统开发过程中,经常会遇到纱线排列的问题. 该问题的描述是这样的:常用纱线的品种一般不会超过25种,所以分别可以用小写字母表示不同的纱线,例如:abc表示三根纱线的排列:重复可以用数字和 ...
- 基于iCamera测试高清摄像头SIV100B(替代ov7670)小结
基于iCamera测试高清摄像头SIV100B(替代ov7670)小结 先看看siv100b主要关键参数 SIV100B与OV7670分辨率和基本特性都差不多,而siv100b,像素尺寸更小,灵敏度更 ...