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 web 程序---登陆验证session。提示登陆

    loigin.jsp <%@ page language="java" import="java.util.*" pageEncoding="g ...

  2. 十九 yield方法

    yield()方法的作用是放弃当前的CPU资源,让 其他任务占用CPU执行时间.但放弃时间不确定, 有可能刚刚放弃,马上又获得CPU时间片.

  3. 《网蜂A8实战演练》——8.Linux USB 主机控制器和设备驱动

    USB 的全称是 Universal Serial Bus,顾名思义:通用串行总线. 提到总线,联想一下,在你心目中总线总是用来干嘛的?还记得 I2C 总线? I2C 总线上挂有二条信号线,一条是 S ...

  4. python学习笔记(十一):网络编程

    一.python操作网络,也就是打开一个网站,或者请求一个http接口,使用urllib模块. urllib模块是一个标准模块,直接import urllib即可,在python3里面只有urllib ...

  5. Running command-line BLAST

    Ubuntu安装BLAST 2014-02-09 10:45:03|  分类: Linux/Ubuntu|举报|字号 订阅     下载LOFTER我的照片书  |     very easy! su ...

  6. cocos2dx切换播放的动画

    版本:cocos2dx 2.2.6 IDE: VS2012 语言:C++98 美术资源一共有两段动画的序列帧,一个是手绘马行走图,一个是分子人行走图. 程序要实现的目的就是在同一个位置,点击按钮可以实 ...

  7. 第四篇 Flask 中的模板语言 Jinja2 及 render_template 的深度用法

    是时候开始写个前端了,Flask中默认的模板语言是Jinja2 现在我们来一步一步的学习一下 Jinja2 捎带手把 render_template 中留下的疑问解决一下 首先我们要在后端定义几个字符 ...

  8. 变体类型 Variant VARIANT

    变体类型 Variant VARIANT class RTL_DELPHIRETURN Variant: public TVarData typedef struct    tagVARIANT  V ...

  9. StringUtils的isNotEmpty和isNotBlank

    StringUtils中一共有130多个方法,并且都是static的,所以我们可以这样调用StringUtils.xxx():今天笔者记录下常用的isNotEmpty和isNotBlank:这两个都是 ...

  10. 迷你MVVM框架 avalonjs 组件编写指南

    avalon经过半年的宣传,已经有不少公司在使用avalon应用于它们内外网应用或移动项目,比较大牌的客户有百度,搜狐,金山,边缘,去哪儿--最近成为去哪儿的前端架构师后,掌握更多资源,可以随使抓个人 ...