在翻阅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原子操作原理的更多相关文章

  1. Atomic原子操作原理剖析

    前言 绝大部分 Objective-C 程序员使用属性时,都不太关注一个特殊的修饰前缀,一般都无脑的使用其非默认缺省的状态,他就是 atomic. @interface PropertyClass @ ...

  2. Linux Kernel CMPXCHG函数分析

    原文地址:http://blog.csdn.net/penngrove/article/details/44175387 最近看到Linux Kernel cmpxchg的代码,对实现很不理解.上网查 ...

  3. 同步(Synchronization)

    多线程应用程序的存在,在运行打开一个潜在的多线程安全的接入资源. 两个线程相同的资源可能会以意想不到的方式改变相互干扰. 例如.一个线程可以覆盖有一个线程改变或使应用程序进入一个潜在的无效的状态未知. ...

  4. java并发机制锁的类型和实现

    synchronized 和 volatile,是最基础的两个锁! volatile是轻量级锁,它在多核处理器开发中保证了共享变量的可见性.即当一个线程修改一个共享变量时,其他线程能够读到这个修改的值 ...

  5. C++程序员面试题目总结(涉及C++基础、多线程多进程、网络编程、数据结构与算法)

     说明:C++程序员面试题目总结(涉及C++基础知识.多线程多进程.TCP/IP网络编程.Linux操作.数据结构与算法) 内容来自作者看过的帖子或者看过的文章,个人整理自互联网,如有侵权,请联系作者 ...

  6. Java并发之原子变量和原子引用与volatile

    我们知道在并发编程中,多个线程共享某个变量或者对象时,必须要进行同步.同步的包含两层作用:1)互斥访问(原子性):2)可见性:也就是多个线程对共享的变量互斥地访问,同时线程对共享变量的修改必须对其他线 ...

  7. Java 理论与实践: 流行的原子——新原子类是 java.util.concurrent 的隐藏精华(转载)

    简介: 在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待.无锁定的算法.在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化.请跟随并 ...

  8. 《Java并发编程实战》第十五章 原子变量与非堵塞同步机制 读书笔记

    一.锁的劣势 锁定后假设未释放.再次请求锁时会造成堵塞.多线程调度通常遇到堵塞会进行上下文切换,造成很多其它的开销. 在挂起与恢复线程等过程中存在着非常大的开销,而且通常存在着较长时间的中断. 锁可能 ...

  9. Java多线程并发编程之原子变量与非阻塞同步机制

    1.非阻塞算法 非阻塞算法属于并发算法,它们可以安全地派生它们的线程,不通过锁定派生,而是通过低级的原子性的硬件原生形式 -- 例如比较和交换.非阻塞算法的设计与实现极为困难,但是它们能够提供更好的吞 ...

随机推荐

  1. 02 JavaScript数据类型、类型转换、注释

    JavaScript 数据类型 JavaScript 变量能够保存多种数据类型:数值.字符串值.数组.对象.undefined.null等等 var length = 7; // 数字 var las ...

  2. Integer的比较==和String的比较==总结

    一.序言 今天发现了一个很有趣的问题,在群里和朋友们讨论的也比较激烈,我现在给大家阐述一下问题. 二.发现问题 上代码... package com.hzwealth.test.question; p ...

  3. python logging模块小记

    1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message') logging.info('This is info messa ...

  4. http://t.cn/xxxxx的短链接如何生成?

    var convertStr = encodeURIComponent(urlStr); //转换的原链接可能存在"&"这样的特殊符号,导致原链接的某些字段会被当做ajax ...

  5. 拿 C# 搞函数式编程 - 2

    前一阵子在写 CPU,导致一直没有什么时间去做其他的事情,现在好不容易做完闲下来了,我又可以水文章了哈哈哈哈哈.顺便成立了自己的专栏:hez2010 的编程日常,欢迎大家关注(逃 有关 FP 的类型部 ...

  6. ThinkPHP5——Session和Cookie

    Session 首先要引入use think\Session:下面使用静态方法调用Session //赋值 Session::set('name','s1'); //赋值think作用域,set(‘名 ...

  7. CSS自定义默认样式

    html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, ...

  8. openstack学习之neutron ml2初始化代码分析

    这里没有 去详细考虑neutron server怎么初始化的,而是直接从加载插件的地方开始分析.首先我们看下下面这个文件. Neutron/api/v2/router.py class APIRout ...

  9. Asp.net MVC + AngularJS 统一权限管理系统(一)

    背景: 之前公司内部做了不少系统,但是权限管理都是分开的:一直都想能够有一套统一管理的权限管理系统:有的时间都是一直在计划,随着时间的流逝,计划始终没有实现,也随着项目的增多而这权限管理也变得版本多样 ...

  10. python数学工具(一)

    python  数学工具包括: 1.函数的逼近 1.1.回归 1.2.插值 2.凸优化3.积分4.符号数学 本文介绍函数的逼近的回归方法 1.作为基函数的单项式 对函数 的拟合 首先定义函数并且可视化 ...