diff --git a/second/week_02/75/AtomicInteger.md b/second/week_02/75/AtomicInteger.md new file mode 100644 index 0000000000000000000000000000000000000000..6ba028a960e75bd03e0e28bc21c38e7dd323ede9 --- /dev/null +++ b/second/week_02/75/AtomicInteger.md @@ -0,0 +1,65 @@ +## AtomicInteger +### introduce +``AtomicInteger是java并发包下面提供的原子类, +主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作。 +原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。 +原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分, +将整个操作视作一个整体是原子性的核心特征。`` +```java +public class AtomicInteger extends Number implements java.io.Serializable { + private static final long serialVersionUID = 6214790243416807050L; + + //获取Unsafe实例 + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long valueOffset; + + static { + try { + //通过Unsafe获取value的偏移量 + valueOffset = unsafe.objectFieldOffset + (AtomicInteger.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } + } + + //包装的int值,volatile主要是保证可见性,即一个线程修改对另一个线程立即可见,主要的实现原理是内存屏障 + private volatile int value; +} +``` +### constructor +```java +public class AtomicInteger { + /** + * Creates a new AtomicInteger with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicInteger(int initialValue) { + //赋初值 + value = initialValue; + } + + /** + * Creates a new AtomicInteger with initial value {@code 0}. + * 默认构造,初始值0 + */ + public AtomicInteger() { + } +} +``` +### important methods +```java +public class AtomicInteger { + /** + * CAS,如果当前值与预期值expect相等,则赋新值update + */ + public final boolean compareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); + } + + /** + * Creates a new AtomicInteger with initial value {@code 0}. + */ + public AtomicInteger() { + } +} +``` \ No newline at end of file diff --git a/second/week_02/75/AtomicStampedReference.md b/second/week_02/75/AtomicStampedReference.md new file mode 100644 index 0000000000000000000000000000000000000000..87481c8dc782f1844fde1130ea94a7bed4869911 --- /dev/null +++ b/second/week_02/75/AtomicStampedReference.md @@ -0,0 +1,73 @@ +## AtomicStampedReference +### introduce +``AtomicStampedReference是java并发包下提供的一个原子类,它能解决其它原子类无法解决的ABA问题。 +ABA问题发生在多线程环境中,当某线程连续读取同一块内存地址两次,两次得到的值一样, +它简单地认为“此内存地址的值并没有被修改过”, +然而,同时可能存在另一个线程在这两次读取之间把这个内存地址的值从A修改成了B又修改回了A, +这时还简单地认为“没有修改过”显然是错误的。`` +```java +public class AtomicStampedReference{ + + //获取Unsafe实例 + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + //获取pair的偏移量 + private static final long pairOffset = + objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class); + + //保存引用和邮戳 + private volatile Pair pair; + + private static class Pair { + //引用 + final T reference; + //邮戳 + final int stamp; + private Pair(T reference, int stamp) { + this.reference = reference; + this.stamp = stamp; + } + //私有化构造,通过of方法获取全新的Pair对象 + static Pair of(T reference, int stamp) { + return new Pair(reference, stamp); + } + } + + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class klazz) { + try { + //调用Unsafe.objectFieldOffset更新Pair + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } + + +} +``` +### important methods +```java +public class AtomicStampedReference{ + public boolean compareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + Pair current = pair; + return + //如果期望引用和当前引用相等 且 期望邮戳和当前邮戳相等 + expectedReference == current.reference && + expectedStamp == current.stamp && + ((newReference == current.reference && + newStamp == current.stamp) || + //如果引用和邮戳都没有变化,并且和新的不完全相同,就构造一个新的Pair对象并执行CAS更新pair。 + casPair(current, Pair.of(newReference, newStamp))); + } + + private boolean casPair(Pair cmp, Pair val) { + return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); + } +} +``` \ No newline at end of file diff --git a/second/week_02/75/LongAdder.md b/second/week_02/75/LongAdder.md new file mode 100644 index 0000000000000000000000000000000000000000..44788819e6140e3e562da3e46d73878682806686 --- /dev/null +++ b/second/week_02/75/LongAdder.md @@ -0,0 +1,124 @@ +## LongAddr +### introduce +``LongAdder是java8中新增的原子类,在多线程环境中,它比AtomicLong性能要高出不少,特别是写多的场景。 +LongAdder的原理是,在最初无竞争时,只更新base的值, +当有多线程竞争时通过分段的思想,让不同的线程更新不同的段,最后把这些段相加就得到了完整的LongAdder存储的值。`` +```java +//LongAddr的父类Striped64 +public class Striped64{ + + /** Number of CPUS, to place bound on table size */ + //CPU核心数,用于设置Cell数组长度 + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + // 分段储存的值 + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + // 单线程时储存值 + transient volatile long base; + + transient volatile int cellsBusy; + + // Unsafe 实例 + private static final sun.misc.Unsafe UNSAFE; + // 储存值 + private static final long BASE; + // 操作锁 0或1 + private static final long CELLSBUSY; + //通过随机数生成的一个值,对于一个确定的线程这个值是固定的 + private static final long PROBE; + + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class sk = Striped64.class; + BASE = UNSAFE.objectFieldOffset + (sk.getDeclaredField("base")); + CELLSBUSY = UNSAFE.objectFieldOffset + (sk.getDeclaredField("cellsBusy")); + Class tk = Thread.class; + PROBE = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomProbe")); + } catch (Exception e) { + throw new Error(e); + } + } +} +``` +### constructor +```java +public class LongAdder{ + /** + * Creates a new adder with initial sum of zero. + */ + //默认空构造 + public LongAdder() { + } +} +``` +### important methods +```java +public class LongAdder{ + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; int m; Cell a; + //as不为空表示已经有多个线程在操作 + if ((as = cells) != null || + //执行cas操作失败,表示有线程正在竞争 + !casBase(b = base, b + x)) { + //预设竞争情况不激烈 + boolean uncontended = true; + //as为空 + if (as == null || (m = as.length - 1) < 0 || + //当前线程对应的Cell为空 + (a = as[getProbe() & m]) == null || + //cas操作失败,表示竞争情况激烈 + !(uncontended = a.cas(v = a.value, v + x))) + //1.初始化Cell 2.进行分段操作 + longAccumulate(x, null, uncontended); + } + } + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, BASE, cmp, val); + } + + //将Cell数组的值合并 + public long sum() { + Cell[] as = cells; Cell a; + long sum = base; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + sum += a.value; + } + } + return sum; + } + + //将Cell数组和base重置为0 + public void reset() { + Cell[] as = cells; Cell a; + base = 0L; + if (as != null) { + for (int i = 0; i < as.length; ++i) { + if ((a = as[i]) != null) + a.value = 0L; + } + } + } +} +``` \ No newline at end of file diff --git a/second/week_02/75/Unsafe.md b/second/week_02/75/Unsafe.md new file mode 100644 index 0000000000000000000000000000000000000000..ad31333f7094b2a7ca9298efe28d0eb0e157cf68 --- /dev/null +++ b/second/week_02/75/Unsafe.md @@ -0,0 +1,112 @@ +## sun.misc.Unsafe + +### introduce +`Unsafe为我们提供了访问底层的机制,这种机制仅供java核心类库使用` +```java +public class Unsafe { + //静态实例 + private static final Unsafe theUnsafe; + + //获取静态实例,如果是非java核心库调用,会抛出SecurityException + @CallerSensitive + public static Unsafe getUnsafe() { + Class var0 = Reflection.getCallerClass(); + if (!VM.isSystemDomainLoader(var0.getClassLoader())) { + throw new SecurityException("Unsafe"); + } else { + return theUnsafe; + } + } + + //在静态代码块为Unsafe的成员变量赋值 + static { + registerNatives(); + Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"}); + theUnsafe = new Unsafe(); + ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class); + ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); + ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class); + ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class); + ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class); + ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class); + ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class); + ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class); + ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class); + ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class); + ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class); + ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class); + ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class); + ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class); + ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class); + ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class); + ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class); + ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class); + ADDRESS_SIZE = theUnsafe.addressSize(); + } +} +``` +### methods +``Unsafe有针对8大基础数据类型及Object的native put和get方法,用于修改和获取私有字段; +此外还有allocateMemory,reallocateMemory,setMemory,copyMemory,freeMemory等操作内存的方法`` +```java +public class Unsafe{ + public native byte getByte(long var1); + + public native void putByte(long var1, byte var3); + + public native short getShort(long var1); + + public native void putShort(long var1, short var3); + + public native char getChar(long var1); + + public native void putChar(long var1, char var3); + + public native int getInt(long var1); + + public native void putInt(long var1, int var3); + + public native long getLong(long var1); + + public native void putLong(long var1, long var3); + + public native float getFloat(long var1); + + public native void putFloat(long var1, float var3); + + public native double getDouble(long var1); + + public native void putDouble(long var1, double var3); + + public native long getAddress(long var1); + + public native void putAddress(long var1, long var3); + + public native long allocateMemory(long var1); + + public native long reallocateMemory(long var1, long var3); + + public native void setMemory(Object var1, long var2, long var4, byte var6); + + public void setMemory(long var1, long var3, byte var5) { + this.setMemory((Object)null, var1, var3, var5); + } + + public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7); + + public void copyMemory(long var1, long var3, long var5) { + this.copyMemory((Object)null, var1, (Object)null, var3, var5); + } + + public native void freeMemory(long var1); +} +``` +## compareAndSwap +``JUC下面大量使用了CAS操作,它们的底层是调用的Unsafe的CompareAndSwapXXX()方法。 +这种方式广泛运用于无锁算法,与java中标准的悲观锁机制相比,它可以利用CAS处理器指令提供极大的加速。`` + +## park/unpark +``JVM在上下文切换的时候使用了Unsafe中的两个非常牛逼的方法park()和unpark()。 +当一个线程正在等待某个操作时,JVM调用Unsafe的park()方法来阻塞此线程。 +当阻塞中的线程需要再次运行时,JVM调用Unsafe的unpark()方法来唤醒此线程。 +我们之前在分析java中的集合时看到了大量的LockSupport.park()/unpark(),它们底层都是调用的Unsafe的这两个方法。`` \ No newline at end of file