diff --git "a/second/week_02/89/AtomicInteger-\346\272\220\347\240\201\345\255\246\344\271\240.md" "b/second/week_02/89/AtomicInteger-\346\272\220\347\240\201\345\255\246\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..1710e33096ae3e3fa0ddffcc0c079cf68746cf5e --- /dev/null +++ "b/second/week_02/89/AtomicInteger-\346\272\220\347\240\201\345\255\246\344\271\240.md" @@ -0,0 +1,12 @@ +#AtomicInteger + +##AtomicInteger源代码相对简单,主要操作是对int值进行加减。主要利用Unsafe类中的cas实现原子操作。 + +##举例 + +```java +public final int addAndGet(int delta) { + //底层调用cas的compareAndSwapInt进行原子操作 + return unsafe.getAndAddInt(this, valueOffset, delta) + delta; + } +``` diff --git "a/second/week_02/89/AtomicStampedReference - \346\272\220\347\240\201\345\255\246\344\271\240.md" "b/second/week_02/89/AtomicStampedReference - \346\272\220\347\240\201\345\255\246\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..d598c5108ac94b445f892fe2962d21578b811a9a --- /dev/null +++ "b/second/week_02/89/AtomicStampedReference - \346\272\220\347\240\201\345\255\246\344\271\240.md" @@ -0,0 +1,37 @@ +#AtomicStampedReference +AtomicStampedReference主要用于解决ABA问题。 + +##Pair +Pair对象利用stamp记录操作版本,用于解决ABA问题 +``` +private static class Pair { + final T reference; + final int stamp; + private Pair(T reference, int stamp) { + this.reference = reference; + this.stamp = stamp; + } + static Pair of(T reference, int stamp) { + return new Pair(reference, stamp); + } + } +``` + +##compareAndSet +```java +public boolean compareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + Pair current = pair; + return + //当前值与预期值相同,版本号相同,表示没有其他线程修改该变量,可以进行更改 +     //如果新值与当前值相同,并且新版本号和现有版本号相同,则无需更改。 +     //如果不同,则尝试使用cas修改内存中变量的值 + expectedReference == current.reference && + expectedStamp == current.stamp && + ((newReference == current.reference && + newStamp == current.stamp) || + casPair(current, Pair.of(newReference, newStamp))); + } +``` \ No newline at end of file diff --git "a/second/week_02/89/LongAdder-\346\272\220\347\240\201\345\255\246\344\271\240.md" "b/second/week_02/89/LongAdder-\346\272\220\347\240\201\345\255\246\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..6a286b1dff5232ea1268fda8b3dadc61d4758ae6 --- /dev/null +++ "b/second/week_02/89/LongAdder-\346\272\220\347\240\201\345\255\246\344\271\240.md" @@ -0,0 +1,101 @@ +#LongAdder +LongAdder有两个主要方法,即add和sum。它更适合用于多线程统计信息计数的情况。在这种有限的情况下,它比AtomicLong更有效。 + +##Add + +首先,像AtomicLong一样,该值将首先由cas更新。当cas更新失败时,尝试将此值拆分成多个值的和。让线程只更新自己的cell,分散竞争压力。 + +```java +public void add(long x) { + Cell[] as; long b, v; int m; Cell a; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + if (as == null || (m = as.length - 1) < 0 || + (a = as[getProbe() & m]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + longAccumulate(x, null, uncontended); + } + } + + + final void longAccumulate(long x, LongBinaryOperator fn, + boolean wasUncontended) { + int h; + 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; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (cellsBusy == 0) { // Try to attach new 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); + } + else if (cellsBusy == 0 && cells == as && casCellsBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + cellsBusy = 0; + } + if (init) + break; + } + else if (casBase(v = base, ((fn == null) ? v + x : + fn.applyAsLong(v, x)))) + break; // Fall back on using base + } + } +``` \ No newline at end of file diff --git "a/second/week_02/89/Unsafe-\346\272\220\347\240\201\345\255\246\344\271\240.md" "b/second/week_02/89/Unsafe-\346\272\220\347\240\201\345\255\246\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..94760d37a1f402848ada52e439c8d288e91b3a0d --- /dev/null +++ "b/second/week_02/89/Unsafe-\346\272\220\347\240\201\345\255\246\344\271\240.md" @@ -0,0 +1,41 @@ +#Unsafe + +##构造方法 + +Unsafe类是一个单例类, 通过静态的getUnsafe()方法获取实例. getUnsafe()方法中有一个权限检查的逻辑,如果不是系统域下的类调用getUnsafe()方法将抛出SecurityException异常.非系统类库要获取Unsafe的实例需要通过反射来调用其事例。 + +```java + public static Unsafe getUnsafe() { + Class cc = sun.reflect.Reflection.getCallerClass(2); + if (cc.getClassLoader() != null) + throw new SecurityException("Unsafe"); + return theUnsafe; + } +``` + + +##管理操作内存 + +```java +//分配内存,返回内存地址 +long allocateMemory(long bytes) +``` + +```java +//释放内存 +void freeMemory(long address) +``` + +```java +//重新分配内存 +long reallocateMemory(long address, long bytes) +``` + +##原子操作 + +```java +//CAS操作包含三个操作数——内存位置、预期原值及新值。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。cas是cpu的原子指令,所以不存在数据不一致问题。多核的情况下cpu进行加锁,锁内存。 +//JDK1.8: getAndAddInt()、getAndSetInt()、getAndAddLong()、getAndSetLong()、getAndAddObject()、getAndSetObject()底层都是cas +compareAndSwapXxx(Object o, long offset, Object expected, Object newValue) +``` +