SpinLock实现,摘自并发编程网

  1. package com.juc.simple;
  2. import java.util.concurrent.atomic.AtomicReference;
  3. /**
  4. * a implement of spinlock based on cas
  5. *
  6. */
  7. public class SpinLock {
  8. private AtomicReference<Thread> sign = new AtomicReference<>();
  9. /**
  10. * 让当前线程不停地的在循环体内执
  11. * 当循环的条件被其他线程改变时 才能进入临界区
  12. */
  13. public void lock() {
  14. Thread current = Thread.currentThread();
  15. //自旋,如果sign为null才能设置为current or memcachedb: checkandset
  16. while (!sign.compareAndSet(null, current)) {
  17. }
  18. }
  19. public void unlock() {
  20. Thread current = Thread.currentThread();
  21. sign.compareAndSet(current, null);
  22. }
  23. }

这里是通过 AtomicReference实现的,而AtomicReference是通过volatile与Unsafe的CAS实现

volatile保证可见性,所有的线程看到的都是最新(主内存?)的值,但是volatile的操作不具有原子性,这样像(a++)这种操作就不能保证安全了,实际是读--修改--写操作的过程

AtomicReference的CAS操作更新值具有原子性

先来一段AtomicReference与volatile的比较

  1. package com.juc.simple;
  2. import java.util.concurrent.atomic.AtomicReference;
  3. public class VolatileVsAtomicReference {
  4. private static volatile Integer volatileVar = 0;
  5. //初始值value为0
  6. private static AtomicReference<Integer> atomicReference=new AtomicReference<Integer>(volatileVar);
  7. public static void main(String[] args) {
  8. try {
  9. testAtomicReference();
  10. testVolatile();
  11. } catch (InterruptedException e) {
  12. System.out.println(e.getMessage());
  13. }
  14. }
  15. public static void testAtomicReference() throws InterruptedException{
  16. for (int i = 0; i < 1000; i++) {
  17. new Thread(new Runnable(){
  18. @Override
  19. public void run() {
  20. for (int i = 0; i < 1000; i++)
  21. while(true){
  22. Integer temp=atomicReference.get();
  23. if(atomicReference.compareAndSet(temp, temp+1)){
  24. break;
  25. }
  26. }
  27. }
  28. }).start();
  29. }
  30. Thread.sleep(1000);
  31. System.out.println("atomicReference "+atomicReference.get()); //1000000
  32. }
  33. public static void testVolatile() throws InterruptedException{
  34. for (int i = 0; i < 1000; i++) {
  35. new Thread(new Runnable(){
  36. @Override
  37. public void run() {
  38. for (int i = 0; i < 1000; i++) {
  39. volatileVar=volatileVar++;
  40. }
  41. }
  42. }).start();
  43. }
  44. Thread.sleep(1000);
  45. System.out.println("volatileVar "+volatileVar); //may 8545
  46. }
  47. }

结果:试过好几次volatileVar值都是不一样的

  1. atomicReference 1000000
  2. volatileVar 8545

这里可以看出如果用了CAS的话AtomicReference是可以保证原子性的,但如果只是简单的get()和set()方法是不行的,其实就等同于volatile,因为这货本身就是volatile实现的

参考

Java volatile reference vs. AtomicReference

oracle官方链接地址

  1. get has the memory effects of reading a volatile variable.
  2. set has the memory effects of writing (assigning) a volatile variable.

Java 理论与实践: 正确使用 Volatile 变量

AtomicReference的原代码实现

  1. package java.util.concurrent.atomic;
  2. import sun.misc.Unsafe;
  3. /**
  4. * An object reference that may be updated atomically. See the {@link
  5. * java.util.concurrent.atomic} package specification for description
  6. * of the properties of atomic variables.
  7. * @since 1.5
  8. * @author Doug Lea
  9. * @param <V> The type of object referred to by this reference
  10. */
  11. public class AtomicReference<V> implements java.io.Serializable {
  12. private static final long serialVersionUID = -1848883965231344442L;
  13. private static final Unsafe unsafe = Unsafe.getUnsafe();
  14. private static final long valueOffset;
  15. static {
  16. try {
  17. valueOffset = unsafe.objectFieldOffset
  18. (AtomicReference.class.getDeclaredField("value"));
  19. } catch (Exception ex) { throw new Error(ex); }
  20. }
  21. //volatile 变量
  22. private volatile V value;
  23. /**
  24. * Creates a new AtomicReference with the given initial value.
  25. *
  26. * @param initialValue the initial value
  27. */
  28. public AtomicReference(V initialValue) {
  29. value = initialValue;
  30. }
  31. /**
  32. * Creates a new AtomicReference with null initial value.
  33. */
  34. public AtomicReference() {
  35. }
  36. /**
  37. * Gets the current value.
  38. *
  39. * @return the current value
  40. */
  41. public final V get() {
  42. return value;
  43. }
  44. /**
  45. * Sets to the given value.
  46. *
  47. * @param newValue the new value
  48. */
  49. //volatile变量赋值
  50. public final void set(V newValue) {
  51. value = newValue;
  52. }
  53. /**
  54. * Eventually sets to the given value.
  55. *
  56. * @param newValue the new value
  57. * @since 1.6
  58. */
  59. //设置为新的值
  60. public final void lazySet(V newValue) {
  61. unsafe.putOrderedObject(this, valueOffset, newValue);
  62. }
  63. /**
  64. * Atomically sets the value to the given updated value
  65. * if the current value {@code ==} the expected value.
  66. * @param expect the expected value
  67. * @param update the new value
  68. * @return true if successful. False return indicates that
  69. * the actual value was not equal to the expected value.
  70. */
  71. //如果当前值与期望值一致,则设置为新的值
  72. public final boolean compareAndSet(V expect, V update) {
  73. return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
  74. }
  75. /**
  76. * Atomically sets the value to the given updated value
  77. * if the current value {@code ==} the expected value.
  78. *
  79. * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  80. * and does not provide ordering guarantees, so is only rarely an
  81. * appropriate alternative to {@code compareAndSet}.
  82. *
  83. * @param expect the expected value
  84. * @param update the new value
  85. * @return true if successful.
  86. */
  87. public final boolean weakCompareAndSet(V expect, V update) {
  88. return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
  89. }
  90. /**
  91. * Atomically sets to the given value and returns the old value.
  92. *
  93. * @param newValue the new value
  94. * @return the previous value
  95. */
  96. //以原子方式设置为新的值,并且返回旧值
  97. public final V getAndSet(V newValue) {
  98. while (true) {
  99. V x = get();
  100. if (compareAndSet(x, newValue))
  101. return x;
  102. }
  103. }
  104. /**
  105. * Returns the String representation of the current value.
  106. * @return the String representation of the current value.
  107. */
  108. public String toString() {
  109. return String.valueOf(get());
  110. }
  111. }

java并发J.U.C AtomicReference VS Volatile的更多相关文章

  1. Java并发J.U.C学习总结

    转载自http://www.cnblogs.com/chenpi/结合自己理解稍有添加自己的理解 阅读目录 JSR 166及J.U.C Executor框架(线程池. Callable .Future ...

  2. java并发:线程同步机制之Volatile关键字&原子操作Atomic

    volatile关键字 volatile是一个特殊的修饰符,只有成员变量才能使用它,与Synchronized及ReentrantLock等提供的互斥相比,Synchronized保证了Synchro ...

  3. Java并发编程、内存模型与Volatile

    http://www.importnew.com/24082.html  volatile关键字 http://www.importnew.com/16142.html  ConcurrentHash ...

  4. Java并发编程学习笔记 深入理解volatile关键字的作用

    引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...

  5. Java并发编程实战3-可见性与volatile关键字

    1. 缓存一致性问题 在计算机中,每条指令都是在CPU执行的,而CPU又不具备存储数据的功能,因此数据都是存储在主存(即内存)和外存(硬盘)中.但是,主存中数据的存取速度高于外存中数据的存取速度(这也 ...

  6. Java并发-J.U.C之AQS

    AQS(Abstract Queue Synchronizer)介绍 [死磕Java并发]—–J.U.C之AQS(一篇就够了) 下面讲解具体的Java并发工具类 1 CountDownLatch 参考 ...

  7. JAVA并发编程:相关概念及VOLATILE关键字解析

    一.内存模型的相关概念 由于计算机在执行程序时都是在CPU中运行,临时数据存在主存即物理内存,数据的读取和写入都要和内存交互,CPU的运行速度远远快于内存,会大大降低程序执行的速度,于是就有了高速缓存 ...

  8. Java并发编程,3分分钟深入分析volatile的实现原理

    volatile原理 volatile简介 Java内存模型告诉我们,各个线程会将共享变量从主内存中拷贝到工作内存,然后执行引擎会基于工作内存中的数据进行操作处理. 线程在工作内存进行操作后何时会写到 ...

  9. Java并发杂谈(一):volatile的底层原理,从字节码到CPU

    volatile的特性 volatile是Java中用于修饰变量的关键字,其主要是保证了该变量的可见性以及顺序性,但是没有保证原子性:其是Java中最为轻量级的同步关键字: 接下来我将会一步步来分析v ...

随机推荐

  1. telnet 传输文件

    用python创建个临时服务器,发送文件供telnet访问 import socket import base64 port = 10005 filename = 'libcrypto.so.1.0. ...

  2. web.xml添加编码过滤器

    解决前后台交互汉字乱码 在项目中的web.xml中添加如下代码: <filter> <filter-name>CharacterEncodingFilter</filte ...

  3. 预处理命令[#define]说明

    宏定义 宏定义是对一些常见的变量.字符串等进行定义,被定义的数据在编译会进行自动替换.有时一些变量或字符串被多次使用,当需要修改时,就需要对源文件中它们出现的地方一一修改,效率比较低,而通过宏定义,只 ...

  4. 耿丹CS16-2班第二次作业汇总

    -- Deadline: 2016-09-28 12:00 -- 作业内容:http://www.cnblogs.com/huangjunlian/p/5891726.html -- 第二次作业总结: ...

  5. Linux kernel4.4.12 添加make menuconfig 可选项

    Linux kernel 源码添加可选项 闲来无事,顺便记录一篇在Linux kernel make menuconfig 内添加一个可选项. 说不定将来就要用到这个东西呢. linux kernel ...

  6. Eclipse导出插件工程

    一.Feature Projecties工程设置 1. 新建一个Feature Projecties 2. 选择我们的插件工程,finish 3. 在目录下新建一个Category definitio ...

  7. [Sass]混合宏的参数

    [Sass]混合宏的参数--传一个不带值的参数 Sass 的混合宏有一个强大的功能,可以传参,那么在 Sass 中传参主要有以下几种情形: A) 传一个不带值的参数 在混合宏中,可以传一个不带任何值的 ...

  8. SQL多表查询,消除表中的重复的内容

    看到朋友再写一个SQL语句:两个表a1表中有SN.SN2.TN,b1表有SM.SM2.TN2,若a1的SN中的数据和b1的SM中的数据是一致的,那么将a1中对应的数据修改成b1中对应的数据. upda ...

  9. 解决Java程序连接mysql数据库出现CommunicationsException: Communications link failure错误的问题

    一.背景 最近在家里捣鼓一个公司自己搭建的demo的时候,发现程序一启动就会出现CommunicationsException: Communications link failure错误,经过一番排 ...

  10. linux的安装

    在CentOS 7中提供了两种桌面"GNOME DESKTOP" 和 "KDE Plasa Workspaces",我们以安装"GNOME DESKT ...