深入浅出 Java Concurrency (2): 原子操作 part 1
转:http://www.blogjava.net/xylz/archive/2010/07/01/324988.html
从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始)。很多情况下我们只是需要一个简单的、高效的、线程安全的递增递减方案。注意,这里有三个条件:简单,意味着程序员尽可能少的操作底层或者实现起来要比较容易;高效意味着耗用资源要少,程序处理速度要快;线程安全也非常重要,这个在多线程下能保证数据的正确性。这三个条件看起来比较简单,但是实现起来却难以令人满意。
通常情况下,在Java里面,++i或者--i不是线程安全的,这里面有三个独立的操作:或者变量当前值,为该值+1/-1,然后写回新的值。在没有额外资源可以利用的情况下,只能使用加锁才能保证读-改-写这三个操作时“原子性”的。
Doug Lea在未将backport-util-concurrent合并到JSR 166里面来之前,是采用纯Java实现的,于是不可避免的采用了synchronized关键字。
public final synchronized void set(int newValue);
public final synchronized int getAndSet(int newValue);
public final synchronized int incrementAndGet();
同时在变量上使用了volatile (后面会具体来讲volatile到底是个什么东东)来保证get()的时候不用加锁。尽管synchronized的代价还是很高的,但是在没有JNI的手段下纯Java语言还是不能实现此操作的。
JSR 166提上日程后,backport-util-concurrent就合并到JDK 5.0里面了,在这里面重复使用了现代CPU的特性来降低锁的消耗。后本章的最后小结中会谈到这些原理和特性。在此之前先看看API的使用。
一切从java.util.concurrent.atomic.AtomicInteger开始。
int addAndGet(int delta)
以原子方式将给定值与当前值相加。 实际上就是等于线程安全版本的i =i+delta操作。
boolean compareAndSet(int expect, int update)
如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 如果成功就返回true,否则返回false,并且不修改原值。
int decrementAndGet()
以原子方式将当前值减 1。 相当于线程安全版本的--i操作。
int get()
获取当前值。
int getAndAdd(int delta)
以原子方式将给定值与当前值相加。 相当于线程安全版本的t=i;i+=delta;return t;操作。
int getAndDecrement()
以原子方式将当前值减 1。 相当于线程安全版本的i--操作。
int getAndIncrement()
以原子方式将当前值加 1。 相当于线程安全版本的i++操作。
int getAndSet(int newValue)
以原子方式设置为给定值,并返回旧值。 相当于线程安全版本的t=i;i=newValue;return t;操作。
int incrementAndGet()
以原子方式将当前值加 1。 相当于线程安全版本的++i操作。
void lazySet(int newValue)
最后设置为给定值。 延时设置变量值,这个等价于set()方法,但是由于字段是volatile类型的,因此次字段的修改会比普通字段(非volatile字段)有稍微的性能延时(尽管可以忽略),所以如果不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修改新值的任务,原线程就不等待修改结果立即返回(这种解释其实是不正确的,但是可以这么理解)。
void set(int newValue)
设置为给定值。 直接修改原始值,也就是i=newValue操作。
boolean weakCompareAndSet(int expect, int update)
如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。JSR规范中说:以原子方式读取和有条件地写入变量但不 创建任何 happen-before 排序,因此不提供与除weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。大意就是说调用weakCompareAndSet时并不能保证不存在happen-before的发生(也就是可能存在指令重排序导致此操作失败)。但是从Java源码来看,其实此方法并没有实现JSR规范的要求,最后效果和compareAndSet是等效的,都调用了unsafe.compareAndSwapInt()完成操作。
下面的代码是一个测试样例,为了省事就写在一个方法里面来了。














































由于这里例子比较简单,这里就不做过多介绍了。
AtomicInteger和AtomicLong、AtomicBoolean、AtomicReference差不多,这里就不介绍了。在下一篇中就介绍下数组、字段等其他方面的原子操作。
参考资料:
(1)http://stackoverflow.com/questions/2443239/java-atomicinteger-what-are-the-differences-between-compareandset-and-weakcompar
(2)http://stackoverflow.com/questions/1468007/atomicinteger-lazyset-and-set
深入浅出 Java Concurrency (2): 原子操作 part 1的更多相关文章
- 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则
转: http://www.blogjava.net/xylz/archive/2010/07/03/325168.html 在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到 ...
- 《深入浅出 Java Concurrency》——原子操作
part1 从AtomicInteger開始 从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包.而Queue.非常多情况下使用到了Atomic操作.因此首 ...
- 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则[转]
在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到锁机制,因此此小节中会适当引入锁的概念. 在Java Concurrency in Practice中是这样定义线程安全的: ...
- 深入浅出 Java Concurrency (3): 原子操作 part 2
转:http://www.blogjava.net/xylz/archive/2010/07/02/325079.html 在这一部分开始讨论数组原子操作和一些其他的原子操作. AtomicInteg ...
- 深入浅出 Java Concurrency (3): 原子操作 part 2[转]
在这一部分开始讨论数组原子操作和一些其他的原子操作. AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API类似,选择有代表性的Atom ...
- 深入浅出 Java Concurrency (2): 原子操作 part 1[转]
从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始).很多情况下我们只是需要一个简单的 ...
- 深入浅出 Java Concurrency (5): 原子操作 part 4 CAS操作
在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...
- 深入浅出 Java Concurrency (5): 原子操作 part 4[转]
在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...
- 深入浅出 Java Concurrency (15): 锁机制 part 10 锁的一些其它问题
主要谈谈锁的性能以及其它一些理论知识,内容主要的出处是<Java Concurrency in Practice>,结合自己的理解和实际应用对锁机制进行一个小小的总结. 首先需要强调的 ...
随机推荐
- Android 颜色渲染(一) 颜色选择器 ColorPickerDialog剖析
版权声明:本文为博主原创文章,未经博主允许不得转载. Android 颜色选择器之ColorPickerDialog剖析 有这样一个需求,可以让用户自定义背景颜色,这就需要提供一个颜色选择器给用户. ...
- exit与return区别
1. exit用于结束正在运行的整个程序,它将参数返回给OS,把控制权交给操作系统:而return 是退出当前函数,返回函数值,把控制权交给调用函数.2. exit是系统调用级别,它表示一个进程的结束 ...
- Qt 学习之路:Canvas
在 QML 刚刚被引入到 Qt 4 的那段时间,人们往往在讨论 Qt Quick 是不是需要一个椭圆组件.由此,人们又联想到,是不是还需要其它的形状?这种没玩没了的联想导致了一个最直接的结果:除了圆角 ...
- Python的Ftplib问题:UnicodeEncodeError: 'latin-1' codec can't encode characters的解决方法
ftplib中有一个方法是cwd,用来切换目录,需要传入一个dirname,经过个人测试,该dirname不能含有汉字,会抛出:UnicodeEncodeError: 'latin-1' codec ...
- 分享一下自己在用的CSS样式重置代码
通过借鉴网上大牛们的经验和自己在工作中碰到的一些问题,总结出了这些比较常用的CSS样式重置的代码: @charset "utf-8"; /* 防止用户自定义背景颜色对网页的影响,添 ...
- xcode本地运行H5游戏可以吗?
答案是不可以!!! 不可以!!! 不可以!!! 有时候很郁闷的接受一个需求,然后以为自己能力不行,或者是代码写错,还是哪里了解不够,然而并不是啊!!! MD的我想说有些事是行不通的的!! 好了,平静下 ...
- ios 动画效果CATransition笔记
初学ios开发,很多概念还不清楚,所以只有边学边做例子.又怕学了后面忘了前面,因此用自己的博客来纪录自己的学习历程,也是对自己学习不要懈怠做个监督. 刚学ios做动画效果.因为ios封装得很好,实现i ...
- 复制JAVABEAN中的属性到另外一个JAVABEAN中
下午写了一个属性复制方法,记录如下: class POUtil{ /** * * Function : 将一个source中的属性到复制到dest * @author : Liaokailin * C ...
- Linux系统、版本、CPU、内存查看、硬盘空间
查看系统版本:lsb_release -a [root@localhost /]# lsb_release -a LSB Version: :core-4.0-amd64:core-4.0-no ...
- 如何学习YII
我是在Yii的官方wiki上看到这篇文章的.读的第一遍觉得很不错,还有一种想翻译出来的冲动.虽然,本人英文很烂,但是毕竟写了这样多年的代码,估计大概的意思是能有的吧.英文原文:http://www.y ...