AtomicReference 这个类和AtomicInteger非常类似,只是AtomicReference对应普通的对象引用,而AtomicInteger 它是对整数的封装,它的方法如下

对weakCompareAndSet 说明:

第一次看weakCompareAndSet doc文档的说明时,我是困惑的。我并不清楚你说的“fail spuriously”和“not provide ordering guarantees”的确切含义。于是我查询了些相关资料。

首先,我从jdk 8 的官方文档的java.util.concurrent.atomic上找到这么二段话:

The atomic classes also support method weakCompareAndSet, which has limited applicability. On some platforms, the weak version may be more efficient than compareAndSet in the normal case, but differs in that any given invocation of the weakCompareAndSet method may return false spuriously (that is, for no apparent reason). A false return means only that the operation may be retried if desired, relying on the guarantee that repeated invocation when the variable holds expectedValue and no other thread is also attempting to set the variable will eventually succeed. (Such spurious failures may for example be due to memory contention effects that are unrelated to whether the expected and current values are equal.) Additionally weakCompareAndSet does not provide ordering guarantees that are usually needed for synchronization control. However, the method may be useful for updating counters and statistics when such updates are unrelated to the other happens-before orderings of a program. When a thread sees an update to an atomic variable caused by a weakCompareAndSet, it does not necessarily see updates to any other variables that occurred before the weakCompareAndSet. This may be acceptable when, for example, updating performance statistics, but rarely otherwise.

一个原子类也支持weakCompareAndSet方法,该方法有适用性的限制。在一些平台上,在正常情况下weak版本比compareAndSet更高效,但是不同的是任何给定的weakCompareAndSet方法的调用都可能会返回一个虚假的失败( 无任何明显的原因 )。一个失败的返回意味着,操作将会重新执行如果需要的话,重复操作依赖的保证是当变量持有expectedValue的值并且没有其他的线程也尝试设置这个值将最终操作成功。( 一个虚假的失败可能是由于内存冲突的影响,而和预期值(expectedValue)和当前的值是否相等无关 )。此外weakCompareAndSet并不会提供排序的保证,即通常需要用于同步控制的排序保证。然而,这个方法可能在修改计数器或者统计,这种修改无关于其他happens-before的程序中非常有用。当一个线程看到一个通过weakCompareAndSet修改的原子变量时,它不被要求看到其他变量的修改,即便该变量的修改在weakCompareAndSet操作之前。

weakCompareAndSet atomically reads and conditionally writes a variable but does not create any happens-before orderings, so provides no guarantees with respect to previous or subsequent reads and writes of any variables other than the target of the weakCompareAndSet.

weakCompareAndSet实现了一个变量原子的读操作和有条件的原子写操作,但是它不会创建任何happen-before排序,所以该方法不提供对weakCompareAndSet操作的目标变量以外的变量的在之前或在之后的读或写操作的保证。

这二段话是什么意思了,也就是说weakCompareAndSet底层不会创建任何happen-before的保证,也就是不会对volatile字段操作的前后加入内存屏障。因为就无法保证多线程操作下对除了weakCompareAndSet操作的目标变量( 该目标变量一定是一个volatile变量 )之其他的变量读取和写入数据的正确性。

AtomicReference 这个类有个问题 就是 如果有2个线程改变了值,最后改回它获取的值,那么程序也会继续执行,可能造成重复执行。例如:为账户低于多少钱用户赠送仅仅-张优惠卷,如果他在获得一张之后,充值了钱又花费了,就会造成多次操作。测试类:

public class AtomicInteget {
public static void main(String[] args) {
AtomicReference<Integer> atomicReference=new AtomicReference<Integer>();
Integer integer = atomicReference.get();
boolean b = atomicReference.compareAndSet(integer, 5);
System.out.println(b);
boolean b1 = atomicReference.compareAndSet(integer, 6);
System.out.println(b1);
boolean b2 = atomicReference.compareAndSet(atomicReference.get(), null);
System.out.println(b2);
System.out.println(atomicReference.get());
boolean b3 = atomicReference.compareAndSet(integer, 6);
System.out.println(b3);
System.out.println(integer);
System.out.println(atomicReference.get());
}
}
结果如下:

true
false
true
null
true
null
6

jdk针对于这种情况,有一个类专门处理这种问题:

AtomicStampedReference<Integer> money = new AtomicStampedReference<Integer>(19, 0);

    public static void main(String args[]) {

        for (int i = 0; i < 100; i++) {
final int timestap = money.getStamp();
new Thread() {
public void run() {
while (true) {
Integer m = money.getReference();
if (m < 20) {
if (money.compareAndSet(m, m + 20, timestap, timestap + 1)) {
System.out.println("余额小于20元,充值成功,余额:" + money.getReference() + "元");
break;
}
} else {
System.out.println("余额大于20,无需充值");
break;
}
}
}
}.start();
} new Thread() {
public void run() {
for (int i = 0; i < 100; i++) { while (true) {
int timestap = money.getStamp();
Integer m = money.getReference();
if (m > 10) {
System.out.println("金额大于10元");
if (money.compareAndSet(m, m - 10, timestap, timestap + 1)) {
System.out.println("成功消费10元,余额:" + money.getReference() + "元");
break;
}
} else {
System.out.println("没有足够的金额");
break;
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start(); }
}

4.4.4 无锁的对象引用:AtomicReference和AtomicStampedReference的更多相关文章

  1. 【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference

    AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用.也就是它可以保证你在修 ...

  2. 无锁的对象引用:AtomicReference

    http://www.dewen.net.cn/q/9588 首先volatile是java中关键字用于修饰变量,AtomicReference是并发包java.util.concurrent.ato ...

  3. 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  4. Java并发 - (无锁)篇6

    , 摘录自葛一鸣与郭超的 [Java高并发程序设计]. 本文主要介绍了死锁的概念与一些相关的基础类, 摘录自葛一鸣与郭超的 [Java高并发程序设计]. 无锁是一种乐观的策略, 它假设对资源的访问是没 ...

  5. Java高并发之无锁与Atomic源码分析

    目录 CAS原理 AtomicInteger Unsafe AtomicReference AtomicStampedReference AtomicIntegerArray AtomicIntege ...

  6. 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁

    1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...

  7. Java高并发-无锁

    一.无锁类的原理 1.1 CAS CAS算法的过程是这样:它包含3个参数CAS(V,E,N).V表示要更新的变量,E表示预期值,N表示新值.仅当V值等于E值时,才会将V的值设为N,如果V值和E值不同, ...

  8. 非阻塞同步算法与CAS(Compare and Swap)无锁算法

    锁(lock)的代价 锁是用来做并发最简单的方式,当然其代价也是最高的.内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的上下文切换和调度延时,等待锁的线程会被挂起直至锁释放. ...

  9. paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象)

    paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象) 1     锁的缺点 2     CAS(Compare ...

随机推荐

  1. java代码-----indexOf()方法--从字符串的某个字符的第一次出现的位子开始

    总结:方法是indedOf()方法.this  is my sister   //indexOf()方法是indexOf('m')==7 .那么就是字符m第一次出现的位置是顺数第7个,就会正常显示‘t ...

  2. Python文件操作,with open as追加文本内容实例

    最常见的读写操作 import re with open('/Users/Mr.Long/Desktop/data.txt', 'w') as f: f.write('hello world') 就这 ...

  3. [转][Java]语法规范

    先来个 阿里的 Java 开发手册(2017.5.20 发布 v1.2.0 .pdf) 本文来自:http://blog.csdn.net/sinat_27115575/article/details ...

  4. linux 文件权限详细说明

    在本章前部,当你试图转换到根用户的登录目录时,你收到了以下消息: cd /root bash: /root: Permission denied 这是 Linux 安全功能的一个演示.Linux 和 ...

  5. mysql 优化 (1)

    提高IOPS能力的几种方法换SSD,PCIE-SSD(提高IO效率,普通SAS盘5000以内的iops,而新设备可达到数万或者数十万iops)少做IO的活(合并多次读写为一次,或者前端加内存CACHE ...

  6. Centos内核参数

    内核参数 abi.vsyscall32 = 1  在2.6.25版本以后的x86-64内核中,默认启用了VDSO32. 虚拟动态共享对象 http://man7.org/linux/man-pages ...

  7. PHP5缓存插件

    1.1操作码介绍及缓存原理 当客户端请求一个PHP程序时,服务器的PHP引擎会解析到该PHP程序,并将其变异为特定的操作码文件(OperateCode opcode),这是要执行的PHP代码的一种二进 ...

  8. 关于where和having的直观理解

    一,查询区别 where是对前面select的字段没有要求,直接查询库表的 having是对前面的select的字段有要求,字段已经select出来的 可以用having进行处理 select id, ...

  9. Spring实战之处理自动装配的歧义性

    仅有一个bean匹配所需的结果时,自动装配才是有效的.如果不仅有一个bean能够匹配结果的话,这种歧义性会阻碍Spring自动装配属性.构造器参数或方法参数.为了阐述自动装配的歧义性,假设我们使用@A ...

  10. Unresolved external 'AlphaBlend' referenced from

    AlphaBlend [Linker Error] Unresolved external 'AlphaBlend' referenced from 解决方案 把文件msimg32.lib添加到工程中 ...