标签:类加载 version array bugs tab 本质 except lin 全局
http://www.cnblogs.com/skywang12345/p/3514589.html
http://www.blogjava.net/xylz/archive/2010/07/01/324988.html
根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类。
java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作。
通常情况下,在Java里面,++i或者--i不是线程安全的,这里面有三个独立的操作:或者变量当前值,为该值+1/-1,然后写回新的值。在没有额外资源可以利用的情况下,只能使用加锁才能保证读-改-写这三个操作时“原子性”的。
该类就是利用现代cpu特性CAS指令,在不加锁的情况下实现i++,这种复合操作的原子性。
其中方法都比较好理解只有两个 lazyset和weakCompareAndSet 不理解。。。
1.8中新增几个类如LongAdder 改类和AtomicLong功能类似,只是更加高效。
http://ifeve.com/atomiclong-and-longadder/
对数组元素的原子更新,包括3个类。
此类的API和AtomicInteger 基本一致,只是修改元素时需要提供元素的索引。 实现几乎一样。
public final int get(int i) {
return unsafe.getIntVolatile(array, rawIndex(i));
}
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int base = unsafe.arrayBaseOffset(int[].class);
private static final int scale = unsafe.arrayIndexScale(int[].class);
private final int[] array;
private long rawIndex(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
return base + (long) i * scale;
}
base: java中数组对象,在存储时都包含一个对象头,这个头部长度可以使用arrayBaseOffset函数获得。
scale: 也就是能指明数组中每个元素占的字节长度。
base + (long) i * scale: 这样就能得出从数组对象头部开始,应该修改哪些字节的元素。
http://www.jb51.net/article/48318.htm
和基本类型的原子类似,都是包装一个类型,只是此处包装了引用类型V,注意 get set 修改的仅仅是引用, 并不是其引用指向的值。
此类方法也比较少,仅仅涉及到对引用的get set ;
各种乐观锁的实现中通常都会用版本戳version来对记录或对象标记,避免并发操作带来的问题,这两个类就是java用类似方法解决ABA。
基于1.8 分析
本质是将两个变量包装在一起,转化为基本类型变量原子更新。
1.8中
private static class Pair<T> { // 对引用T和int值包装,
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair; //确保修改立即可见
public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference && expectedStamp == current.stamp && casPair(current, Pair.of(newReference, newStamp))); // CAS 直接更新包装对象引用
}
private boolean casPair(Pair<V> cmp, Pair<V> val) { //CAS更新引用
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
目标: 做到对引用T和int变量 原子更新(同时更改这两个变量);
当同时调用compareAndSet时,二者会先判断当前状态是否是(10,0), 符合,所以两个线程都可能会创建新的Pair对象,1创建(20,1); 2创建(60,1),接下来就会调用casPair 更新当前pair引用, 两个线程虽然都已经创建新的Pair对象,但是只能有一个线程更新成功。 (此处问题就化简为对基本类型原子更新)
1.6 中基本原理和1.8一致,只是更加繁琐,对于Pair对象引用的原子更新 又调用了AtomicReference来实现,而1.8则直接将该Pair(打包对象)设置为volatile。
可以对指定对象的volatile int‘类型的成员"进行原子更新。它是基于反射原理实现的。
该类是抽象类,具体的实现是由其内部类实现。
该类的实现和2中对数组元素的原子更新类似,
数组i位置元素CAS更新时,依据传入索引i得出需要修改的内存位置(相对于数组起始位置),然后对该内存块调用底层CAS更新。
该类同类,对对象a的int变量b CAS更新时,在创建该原子类时就会计算出变量b在a对象中的存储位置,更新时就会直接对该内存块CAS更新。
offset就是int 变量在该对象中的相对偏移值,在构造函数中就会计算出来。
构造函数中会检查需要更新的变量是否是volatile int,如果不是就会抛出异常、
标签:类加载 version array bugs tab 本质 except lin 全局
原文地址:http://www.cnblogs.com/yuan7712/p/6817135.html