Java 原子类 java.util.concurrent.atomic
1、i++为什么是非线程安全的
i++其实是分为3个步骤:获取i的值, 把i+1, 把i+1的结果赋给i
如果多线程执行i++操作,没有同步的话,结果可能不正确
如两个线程同时获取i的值,然后各自+1后,赋给i。正确的情况下i的值应该是加了2,但这里其实加了1而且,前面的结果被覆盖了。
通常做法:synchronized (synchronized方法,synchronized变量), 但这样做效率不是最优的。
2、AtomicInteger的实现
主要依靠:1、volatile 保证了变量的可见性,所有线程不缓存volatile变量,需要时都从内存读取,这样能保证所有数据拿到的值都是最新的。
2、compareAndSet(int expect, int update)判断当前值==expect?当前值=update:错误;
这里做了两步操作,判断跟赋值。但因为cpu提供这样指令的支持,所有能保证这个操作时原子的。
- public class AtomicIntegerextends Number
implements java.io.Serializable { - private staticfinal
long serialVersionUID = 6214790243416807050L; - // setup to use Unsafe.compareAndSwapInt for updates
- private staticfinal Unsafe unsafe = Unsafe.getUnsafe();
- private staticfinal
long valueOffset; - static {
- try {
- valueOffset = unsafe.objectFieldOffset
- (AtomicInteger.class.getDeclaredField("value"));
- } catch (Exception ex) {
throw new Error(ex); } - }
- private volatileint value;
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value;
3、AtomicInteger 中的set(int newValue) lazySet(int newValue)
void set(int newValue)
设置为给定值。 直接修改原始值,也就是i=newValue操作。
void lazySet(int newValue) 最后设置为给定值。
延时设置变量值,这个等价于set()方法,但是由于字段是volatile类型的,因此次字段的修改会比普通字段(非volatile字段)有稍微的性能延时(尽管可以忽略),所以如果不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修改新值的任务,原线程就不等待修改结果立即返回(这种解释其实是不正确的,但是可以这么理解)。
4、AtomicInteger中compareAndSet(int expect, int update) weakCompareAndSet(int expect, int update)
boolean weakCompareAndSet(int expect, int update)
如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。JSR规范中说:以原子方式读取和有条件地写入变量但不
创建任何 happen-before 排序,因此不提供与除weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。大意就是说调用weakCompareAndSet时并不能保证不存在happen-before的发生(也就是可能存在指令重排序导致此操作失败)。但是从Java源码来看,其实此方法并没有实现JSR规范的要求,最后效果和compareAndSet是等效的,都调用了unsafe.compareAndSwapInt()完成操作。
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- *
- * @param expect the expected value
- * @param update the new value
- * @return true if successful. False return indicates that
- * the actual value was not equal to the expected value.
- */
- public finalboolean compareAndSet(int expect,int
update) { - return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
- }
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- *
- * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
- * and does not provide ordering guarantees, so is only rarely an
- * appropriate alternative to {@code compareAndSet}.
- *
- * @param expect the expected value
- * @param update the new value
- * @return true if successful.
- */
- public finalboolean weakCompareAndSet(int expect,int
update) { - return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
- }
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
} /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
* and does not provide ordering guarantees, so is only rarely an
* appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @return true if successful.
*/
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}