原子变量和原子操作
来源:互联网 发布:win7网络连接有个红叉 编辑:程序博客网 时间:2024/04/28 10:36
原子变量和原子操作
通常情况下,在Java里面,++i或者–i不是线程安全的,这里面有三个独立的操作:获得变量当前值,为该值+1/-1,然后写回新的值。在没有额外资源可以利用的情况下,只能使用加锁才能保证读-改-写这三个操作是“原子性”的。
Java 5新增了AtomicInteger类,该类包含方法getAndIncrement()以及getAndDecrement(),这两个方法实现了原子加以及原子减操作,但是比较不同的是这两个操作没有使用任何加锁机制,属于无锁操作。
CAS操作(Compare and Swap)
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
现代的CPU提供了特殊的指令,可以自动更新共享数据,而且能够检测到其他线程的干扰,而 compareAndSet() 就用这些代替了锁定。
拿AtomicInteger来研究在没有锁的情况下是如何做到数据正确性的。
private volatile int value;
首先毫无疑问,在没有锁的机制下需要借助volatile原语,保证线程间的数据是可见的(共享的),这样获取变量值的时候才能直接读取。
public final int get() { return value; }
然后来看看++i是怎么做到的(jdk1.7)。
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; }}
在这里采用了CAS操作,每次从内存中读取数据然后将此数据和+1后的结果进行CAS操作,如果成功就返回结果,否则重试直到成功为止。而compareAndSet利用JNI来完成CPU指令的操作。
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
综上,我们可以总结出AtomicInteger实现CAS操作的大致思想。首先volatile保证每次get()方法取到的值都是公共栈内的最新值,当然,这并不保证此值接下来不会被其他线程修改。所以要在incrementAndGet()方法中进行检查,检查的关键是compareAndSet()方法,它首先通过this参数和valueOffset参数获得现在在公共栈中的AtomicInteger值,如果和expenct相同,那么说明get()方法取回的值并没有被修改,那么将AtomicInteger的value属性更新为update,并返回true;否则什么也不干并返回false。
valueOffset是一个long参数,代表AtomicInteger参数的value字段相对于此类的偏移量,通过这个参数配合AtomicInteger对象本身,可以找到此时的真实的value字段。
AtomicInteger实现CAS操作的基本原理可以总结为两句话:
1. 尽管AtomicInteger存储的字段可以被其他线程修改,但是存储字段的位置是不变的,这使得我们可以在一个线程内随时得到此类的真实value字段,这是进行CAS检查的基础。
2. 在线程内得到真实值后与原先值进行比较,也就是current字段,如果相同,则说明无其他线程修改这个值,可以进行替换,否则不进行替换。
在此基础上,我们可以试着描述如果在current+1过程中AtomicInteger的value字段被修改了会怎么样?
在jdk1.8中,incrementAndGet直接使用了Unsafe的getAndAddInt方法,而在jdk1.7的Unsafe中,没有此方法。
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
- 原子变量和原子操作
- Java原子变量&原子操作
- Java多线程/并发16、Atomic原子变量和原子操作
- 原子变量的操作
- 线程4:原子变量与原子操作
- volatile和原子操作
- 原子操作和信号量
- 原子操作和锁
- volatile和原子操作
- volatile和原子操作
- 原子操作和竞争
- java并发中的原子变量和原子操作以及CAS介绍
- 原子变量
- 原子变量
- 条件变量和原子型式
- 原子变量和CAS算法
- 原子变量 和cas 原理
- linux内核原子变量与原子位操作API
- 剑指offer 面试题47 不用加减乘除做加法
- Markdown添加空格效果
- 如何解决Failed to load class "org.slf4j.impl.StaticLoggerBinder".
- java线程池常见问题
- POJ 1734 Sightseeing trip 笔记
- 原子变量和原子操作
- PostgreSQL常用命令
- javaweb分页查询
- 通缩
- GOLANG
- centos6.8 yum安装mysql 5.6
- [BZOJ3625][Codeforces Round #250][多项式求逆][多项式开根]小朋友和二叉树
- Python学习笔记(3) -- enumerate函数
- Android handler讲解与实践