java并发包中的原子操作类,这些类都是基于非阻塞算法CAS实现的。
4.1原子变量操作类
AtomicInteger/AtomicLong/AtomicBoolean等原子操作类
AtomicLong类:
public class AtomicLong extends Number implements java.io.Serializable { // 基于硬件的原子操作类 private static final Unsafe unsafe = Unsafe.getUnsafe(); // 存放value的偏移地址 private static final long valueOffset; //判断jvm是否支持Long类型无锁CAS static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); private static native boolean VMSupportsCS8(); // 初始化value字段的偏移量 static { try { valueOffset = unsafe.objectFieldOffset (AtomicLong.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } // 存放具体的值 private volatile long value; ......... }
虽然该类提供了原子操作(虽然是无阻塞的CAS操作,相对于阻塞算法提升了很火),但是在高并发情况下,会竞争更新同一个原子变量,仍然会有效率问题。
导致问题的原因也就是CAS操作:
public final long getAndAddLong(Object paramObject , long paramLongl , long paramLong2) long l ; do { 1 = getLongvolatile(paramObject , paramLongl) ; // .compareAndSwapLong比较交换操作,该方法就是CAS的核心方法,但是该方法在高并发情况下,会竞争更新原子变量,最终只有一个线程更新成功,其他线程会循环多次CAS操作,浪费了cpu资源,降低了效率 ) while (!compareAndSwapLong(param0bject , paramLongl , 1, 1 + paramLong2) ); return l ; }compareAndSwapLong:paramObject操作对象,paramLong1 value的偏移量,第三个参数为except表示当前是否是该值,最后一个参数就是要修改成的值
jdk8新增的原子操作类LongAdder
为了解决高并发情况下多线程对一个共享变量的CAS争夺失败后进行自旋而造成的降低并发性能的问题,LongAdder在内部维护了一个cell元素(一个动态的cell数组)来分担对单个变量进行争夺的开销,也就是将对一个变量的争夺分配到对多个变量的争夺上。
LongAdder结构:继承Striped64
Striped64类,Cell类上有一个Contented注解,作用是避免伪共享问题
// 一个内部类,LongAdder就是通过Cell对象来提高性能,降低自选的CAS操作 @sun.misc.Contended static final class Cell { volatile long value; Cell(long x) { value = x; } final boolean cas(long cmp, long val) { return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); } // Unsafe类,基于硬件的原子操作类 private static final sun.misc.Unsafe UNSAFE; // value在Cell对象内存地址中的偏移量 private static final long valueOffset; // 静态代码块 初始化Unsafe类,和偏移量valueOfset static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class<?> ak = Cell.class; valueOffset = UNSAFE.objectFieldOffset (ak.getDeclaredField("value")); } catch (Exception e) { throw new Error(e); } } } /** Number of CPUS, to place bound on table size */ static final int NCPU = Runtime.getRuntime().availableProcessors(); // cell数组,每一个线程会争夺一个cell对象,cell数组变相的降低了争夺一个变量的性能问题 transient volatile Cell[] cells; // LongAdder的真实值就是base+cell[0]...+cell[n] transient volatile long base; // 为了实现自旋锁,状态值只有0和1 transient volatile int cellsBusy;
LongAdder重点方法add():
当内部increment或decrement自增或自减操作是,内部调用的就是add方法,当cell数组为空时,默认走的就是casBase方法(此时和AtomicLong操作相同,即都是在base的基础上进行累加或累减操作的)。
进入第3行if判断的情况:
1:cells不为空,会进入if
假如cells不为空进入的if判断,则第5行结果为false,第6行会判断Thread对象中的threadLocalRandomProbe的值是否存在,不存在,则直接调用longAccumulate方法,存在的话,会进一步判断a.cas操作是否成功,不成功则调用longAccumulate方法,成功则代表add方法累加成功
2:casBase操作失败,会进入if
如果cells为空,casBase方法操作失败,则进入if判断中,且第5行为true,则直接调用longAccumulate方法
1 public void add(long x) { 2 Cell[] as; long b, v; int m; Cell a; 3 if ((as = cells) != null || !casBase(b = base, b + x)) { 4 boolean uncontended = true; 5 if (as == null || (m = as.length - 1) < 0 || 6 (a = as[getProbe() & m]) == null || 7 !(uncontended = a.cas(v = a.value, v + x))) 8 longAccumulate(x, null, uncontended); 9 } 10 } 11 12 /** 13 * Equivalent to {@code add(1)}. 14 */ 15 public void increment() { 16 add(1L); 17 } 18 19 /** 20 * Equivalent to {@code add(-1)}. 21 */ 22 public void decrement() { 23 add(-1L); 24 }
longAccumulate方法是进行cells数组初始化和扩容的地方
final void longAccumulate(long x, LongBinaryOperator fn, boolean wasUncontended) { int h; // 初始化probe,也就是Thread类中的threadlocalsRandomProbe变量 if ((h = getProbe()) == 0) { ThreadLocalRandom.current(); // force initialization h = getProbe(); wasUncontended = true; } boolean collide = false; // True if last slot nonempty // 死循环 for (;;) { Cell[] as; Cell a; int n; long v; // 这里和上边add方法的两种情况对应,一种是cells不为null,一种是未null,当前if为cells不为null的时候会进入 if ((as = cells) != null && (n = as.length) > 0) { // as[(n-1) & h] 里边的索引和上一步add方法中的相同,都是通过probe的值 并上 cells数组的长度减1, 这一块就是获取线程应该访问的Cell对象(相当于AtomicLong对象中的共享变量) if ((a = as[(n - 1) & h]) == null) { if (cellsBusy == 0) { // Try to attach new Cell 当前索引处无Cell对象,并且没有线程在执行CAS操作,则会新建一个Cell对象 Cell r = new Cell(x); // Optimistically create if (cellsBusy == 0 && casCellsBusy()) { boolean created = false; try { // Recheck under lock Cell[] rs; int m, j; if ((rs = cells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) { rs[j] = r; created = true; } } finally { cellsBusy = 0; } if (created) break; continue; // Slot is now non-empty } } collide = false; } else if (!wasUncontended) // CAS already known to fail wasUncontended = true; // Continue after rehash else if (a.cas(v = a.value, ((fn == null) ? v + x : fn.applyAsLong(v, x)))) break; else if (n >= NCPU || cells != as) collide = false; // At max size or stale else if (!collide) collide = true; else if (cellsBusy == 0 && casCellsBusy()) { try { if (cells == as) { // Expand table unless stale Cell[] rs = new Cell[n << 1]; for (int i = 0; i < n; ++i) rs[i] = as[i]; cells = rs; } } finally { cellsBusy = 0; } collide = false; continue; // Retry with expanded table } h = advanceProbe(h); } // 以下判断是当cells为null时,并且cellsBusy为0,并且能够将cellsBusy自增为1时,也就是能够加锁时,进入判断内 else if (cellsBusy == 0 && cells == as && casCellsBusy()) { boolean init = false; try { // Initialize table if (cells == as) { // 默认初始化Cell数组大小为2 Cell[] rs = new Cell[2]; rs[h & 1] = new Cell(x); cells = rs; init = true; } } finally { cellsBusy = 0; } if (init) break; } // 以上条件都不满足,如果指定了operation方法,则使用operation进行操作,没有的话,则进行累加操作(这块是针对自定义operation的) else if (casBase(v = base, ((fn == null) ? v + x : fn.applyAsLong(v, x)))) break; // Fall back on using base } }
LongAccumulator类:LongAdder是LongAccumulator的一个特例,后者提供了更加强大的功能,可以让用户自定义累加规则
public LongAccumulator(LongBinaryOperator accumulatorFunction, long identity) { this.function = accumulatorFunction; base = this.identity = identity; } // java8中的函数式接口可以自定义操作规则,累加、累乘等操作 @FunctionalInterface public interface LongBinaryOperator { /** * Applies this operator to the given operands. * * @param left the first operand * @param right the second operand * @return the operator result */ long applyAsLong(long left, long right); }