From f1f69b701da5abfe5005ad3927855ac586cde68f Mon Sep 17 00:00:00 2001 From: sj-java <2686583079@qq.com> Date: Wed, 18 Dec 2019 15:18:09 +0800 Subject: [PATCH] week02 --- week_02/54/AtomicInteger-054.md | 96 ++++++++++++ week_02/54/AtomicStampedReference-054.md | 90 +++++++++++ week_02/54/LongAdder-054.md | 189 +++++++++++++++++++++++ week_02/54/Unsafe-054.md | 179 +++++++++++++++++++++ 4 files changed, 554 insertions(+) create mode 100644 week_02/54/AtomicInteger-054.md create mode 100644 week_02/54/AtomicStampedReference-054.md create mode 100644 week_02/54/LongAdder-054.md create mode 100644 week_02/54/Unsafe-054.md diff --git a/week_02/54/AtomicInteger-054.md b/week_02/54/AtomicInteger-054.md new file mode 100644 index 0000000..5e894ba --- /dev/null +++ b/week_02/54/AtomicInteger-054.md @@ -0,0 +1,96 @@ +##基于jdk1.8的AtomicInteger分析 + +大概看了一下源码,底层是基于Unsafe来实现的,原子类的Integer类,线程安全 + +// setup to use Unsafe.compareAndSwapInt for updates +private static final Unsafe unsafe = Unsafe.getUnsafe();//获取Unsafe实例 + +//初始化valueOffset,获取到内存的偏移量 +private static final long valueOffset; + +static { + try { + //调用Unsafe的方法获取偏移量 + valueOffset = unsafe.objectFieldOffset + (AtomicInteger.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } +} + +//利用volatile保证了每个线程所看到的value是一样的 +private volatile int value; + +#####构造方法 +/** + * Creates a new AtomicInteger with the given initial value. + * + * @param initialValue the initial value + */ + //传入一个Int值赋值给value +public AtomicInteger(int initialValue) { + value = initialValue; +} + +/** + * Creates a new AtomicInteger with initial value {@code 0}.//值为0 + */ +public AtomicInteger() { +} + +#####主要方法 +/** + * 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 {@code 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) { +//通过Unsafe的CAS来实现 + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); +} + +/** + * Atomically sets the value to the given updated value + * if the current value {@code ==} the expected value. + * + *

May fail + * spuriously 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 {@code true} if successful + */ +public final boolean weakCompareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); +} + +//上面两个方法一模一样,但是weakCompareAndSet给出的注释里面有可能虚假的失败,因此有少时候需要代替compareAndSwapInt +//在一些平台上面weakCompareAndSet比compareAndSwapInt效率高 +//weakCompareAndSet实现了一个变量原子的读操作和有条件的原子写操作, +//但是它不会创建任何happen-before排序, +//所以该方法不提供对weakCompareAndSet操作的目标变量以外的变量的在之前或在之后的读或写操作的有序保证 + + /** + * Atomically increments by one the current value. + * + * @return the previous value + */ +public final int getAndIncrement() { +//实际上就是获取到valueOffset,进行+1然后赋值给next不断的compareAndSwapInt + return unsafe.getAndAddInt(this, valueOffset, 1); +} + +//Unsafe类 +public final int getAndAddInt(Object var1, long var2, int var4) { +//传入var4为1 + int var5;//初始化偏移量值 + do { + var5 = this.getIntVolatile(var1, var2); + //判断是否更新,没更新就是var5,更新了就是var5+1 + } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); + + return var5; +} \ No newline at end of file diff --git a/week_02/54/AtomicStampedReference-054.md b/week_02/54/AtomicStampedReference-054.md new file mode 100644 index 0000000..646f784 --- /dev/null +++ b/week_02/54/AtomicStampedReference-054.md @@ -0,0 +1,90 @@ +##基于jdk1.8的AtomicStampedReference源码分析 + +通过计数的方式解决了ABA问题 + +#### Pair类 +private static class Pair { +//将值和版本号封装为一个Pair,比较就是比较这个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); + } +} +//设置成volatile,保证每个线程可见 +private volatile Pair pair; + +####构造方法 + /** + * Creates a new {@code AtomicStampedReference} with the given + * initial values. + * + * @param initialRef the initial reference + * @param initialStamp the initial stamp + */ +public AtomicStampedReference(V initialRef, int initialStamp) { +//把需要修改的值封装成pair + pair = Pair.of(initialRef, initialStamp); +} + +####主要方法 + /** + * Returns the current value of the reference. + * + * @return the current value of the reference + */ +public V getReference() { + //获取到pair里面的值 + return pair.reference; +} + +/** + * Returns the current value of the stamp. + * + * @return the current value of the stamp + */ +public int getStamp() { +//获取版本号 + return pair.stamp; +} + +**CAS** + +/** + * Atomically sets the value of both the reference and stamp + * to the given update values if the + * current reference is {@code ==} to the expected reference + * and the current stamp is equal to the expected stamp. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedStamp the expected value of the stamp + * @param newStamp the new value for the stamp + * @return {@code true} if successful + */ +public boolean compareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + //通过版本号解决ABA问题 + Pair current = pair; + return + //比较值 + expectedReference == current.reference && + //修改的次数 + expectedStamp == current.stamp && + ((newReference == current.reference && + newStamp == current.stamp) || + casPair(current, Pair.of(newReference, newStamp))); +} + +private boolean casPair(Pair cmp, Pair val) { +//调用Unsafe的CAS + return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); +} \ No newline at end of file diff --git a/week_02/54/LongAdder-054.md b/week_02/54/LongAdder-054.md new file mode 100644 index 0000000..36238d9 --- /dev/null +++ b/week_02/54/LongAdder-054.md @@ -0,0 +1,189 @@ +##基于jdk1.8LongAdder源码分析 + +高并发下面使用计数 + +####类的开头 +public class LongAdder extends Striped64 implements Serializable { +} + +**Striped64类分析** + +//集成了Striped64类,从而实现累加的功能 +//Striped64通过内部的分散算法来避免竞争 +//Striped64内部包含了Cell数组和base,都是volatile关键字修饰的 +//1.当没有竞争的情况下,通过cas累加到base上面 +//2.存在竞争的情况下,累加的数会放在Cell数组的cell元素上面 +//整个Striped64的值为base+sum(Cell) + +//存放cell的hash表,大小为2的幂 +transient volatile Cell[] cells; +//基础值,没有竞争的时候会更新这个值,在Cell初始化的时候,也会尝试往上面累加 +transient volatile long base; +//自旋锁,通过CAS加锁,保护Cell创建和扩展,值为0or1 +transient volatile int cellsBusy; + + +####构造函数 + +/** + * Creates a new adder with initial sum of zero. + */ +public 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; + //如果cells不为null,则表示没有竞争,如果cells为null,表示不存在竞争,则直接通过cas直接赋值给base + if ((as = cells) != null || !casBase(b = base, b + x)) { + //没有竞争标记为true false代表存在竞争 + boolean uncontended = true; + //1.as==null表示不存在竞争,cells数组没有被初始化 + //2.(m = as.length - 1) < 0表示cells数组长度为0 + //1和2都表示cells数组没有被初始化 + //3.(a = as[getProbe() & m]) == null 表示cells对应的下标值为null, + //如果为null,则没有进行过累加,创建一个新的Cell对象 + //4.!(uncontended = a.cas(v = a.value, v + x)) 通过cas进行累加和比较赋值给uncontended + //总体来说1和2表示cells没有被初始化,3表示没有进行累加,4表示产生了冲突 + 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); + } +} + +/** + * Returns the probe value for the current thread. + * Duplicated from ThreadLocalRandom because of packaging restrictions. + */ +static final int getProbe() { +//返回当前线程的地址 + return UNSAFE.getInt(Thread.currentThread(), PROBE); +} + +/** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention.(处理涉及初始化、调整大小和,创建新单元格或者争用) + * See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param fn the update function, or null for add (this convention + * avoids the need for an extra field or function in LongAdder). + * @param wasUncontended false if CAS failed before call + */ +final void longAccumulate(long x, LongBinaryOperator fn, + boolean wasUncontended) { + int h; + //获取当前线程的地址值最为hash值 + 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; + //表示cells已经被初始化 + if ((as = cells) != null && (n = as.length) > 0) { + //表示还没有被设置过值 + if ((a = as[(n - 1) & h]) == null) { + //表示没有线程对cells数组做修改 + if (cellsBusy == 0) { // Try to attach new Cell + //创建新的Cell对象 + Cell r = new Cell(x); // Optimistically create + //表示没有线程对cells数组做修改并且通过cas设置cellsBusy为1加锁 + if (cellsBusy == 0 && casCellsBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + //再次检测cells数组是否为空且对应的位置是否为null + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + //赋值r到该位置 + rs[j] = r; + created = true; + } + } finally { + //去掉锁 + cellsBusy = 0; + } + //设置成功跳出循环,没有成功继续循环,表示该位置已经被设置值了 + if (created) + break; + continue; // Slot is now non-empty + } + } + //表示cellsBusy=1,有线程在更改cells数组,产生了冲突 + collide = false; + } + //cas失败,需要重新执行 + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + //cas比较新的线程和当前线程的值,如果有线程参与,对v进行直接加到value + 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; + //扩容cell数组 + 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 + } + //重新计算hash值 + h = advanceProbe(h); + } + //表示cells还没有被初始化,尝试获取cellsBusy的锁 + else if (cellsBusy == 0 && cells == as && casCellsBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + //初始化数组,容量为2,放入x到0或者1的位置 + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + //解锁 + cellsBusy = 0; + } + //表明初始化成功 + if (init) + break; + } + //尝试累加到base上面 + 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/week_02/54/Unsafe-054.md b/week_02/54/Unsafe-054.md new file mode 100644 index 0000000..5996bcd --- /dev/null +++ b/week_02/54/Unsafe-054.md @@ -0,0 +1,179 @@ +##基于jdk1.8的Unsafe分析 + +原子类最核心的模块,很多类都是基于Unsafe里面来实现的 + +####本地方法 +//本地静态方法 在静态块中执行 +private static native void registerNatives(); + +####构造函数 +//私有构造方法 不能被实例化 +private Unsafe() { + } + +####主要方法 + +######获取实例的方法 + +//@CallerSensitive堵住漏洞 防止双重反射获取 +@CallerSensitive +public static Unsafe getUnsafe() { + Class var0 = Reflection.getCallerClass(); + if (!VM.isSystemDomainLoader(var0.getClassLoader())) { + //判断是否是系统的类加载器加载 不是抛出SecurityException异常 + throw new SecurityException("Unsafe"); + } else { + return theUnsafe; + } +} + +#####读写 + +//Object可以为null,var2表示 + public native int getInt(Object var1, long var2); + +public native void putInt(Object var1, long var2, int var4); + +#####读写地址 + +//获取内存地址的值,如果地址是 0 或者不是指向通过 allocateMemory 方法获取的内存块, +//则结果是未知的 +public native byte getByte(long var1); + +public native void putByte(long var1, byte var3); + +#####本地内存 +//分配指定大小的一块本地内存。这块内存不会被初始化,里面的内容通常是没有用处的数据 +//返回的地址不会是0 且内存块是连续的 +public native long allocateMemory(long var1); + +//重新分配一块指定大小的内存,超出老内存块的字节不会被初始化 +//当请求为0 时,返回的本地指针也为0,如果var1为null,方法则和allocateMemory一样 +public native long reallocateMemory(long var1, long var3); +//将给定的内存块所有字节设置成固定的值(通常是0) +//通过前面两个参数确定内存块的基准地址 有点类似于上面的getInt()方法 +//double-register 地址模型 +public native void setMemory(Object var1, long var2, long var4, byte var6); + +//将给定的内存块所有字节设置成固定的值(通常是0) +//直接传过来是var1地址 +//single-register地址模型 +public void setMemory(long var1, long var3, byte var5) { + this.setMemory((Object)null, var1, var3, var5); +} + +//复制一块内存块里面的字节到另外的内存块,double-register 地址模型 +public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7); + +//复制一块内存块里面的字节到另外的内存块,single-register地址模型 +public void copyMemory(long var1, long var3, long var5) { + this.copyMemory((Object)null, var1, (Object)null, var3, var5); +} + +//释放allocateMemory和reallocateMemory的内存,如果var1为null,不做任何处理 +public native void freeMemory(long var1); + +#####获取类的变量 +//返回字段的偏移量 +@Deprecated +public int fieldOffset(Field var1) { +//判断是否为静态方法,两者调用的本地方法不一样 + return Modifier.isStatic(var1.getModifiers()) ? (int)this.staticFieldOffset(var1) : (int)this.objectFieldOffset(var1); +} + +//返回访问静态字段的地址 +@Deprecated +public Object staticFieldBase(Class var1) { +//获取所有的字段 + Field[] var2 = var1.getDeclaredFields(); + + for(int var3 = 0; var3 < var2.length; ++var3) { + //获取静态字段 + if (Modifier.isStatic(var2[var3].getModifiers())) { + return this.staticFieldBase(var2[var3]); + } + } + + return null; +} + +//返回给定字段在该类的偏移量地址 +//对于任何给的字段都返回同一个值,同一个类不同的字段总是不同的值 +public native long staticFieldOffset(Field var1); + +//返回给定字段的字节偏移量 +public native long objectFieldOffset(Field var1); + +//返回给定字段的位置 +public native Object staticFieldBase(Field var1); + +//检查给定的类是否需要初始化 +public native boolean shouldBeInitialized(Class var1); + +//确定给定的类完成初始化 +public native void ensureClassInitialized(Class var1); + +#####**CAS相关 +//如果变量的值为预期值,则更新变量的值,该操作为原子操作,修改成功返回为true + public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); + +public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); + +public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6); + +#####**volatile相关 +//对于给定的操作,有volatile语句,其他和getObject一样,为了保证不同线程之间的可见性 + +public native Object getObjectVolatile(Object var1, long var2); + +public native void putObjectVolatile(Object var1, long var2, Object var4); + +public native int getIntVolatile(Object var1, long var2); + +public native void putIntVolatile(Object var1, long var2, int var4); + +public native boolean getBooleanVolatile(Object var1, long var2); + +public native void putBooleanVolatile(Object var1, long var2, boolean var4); + +public native byte getByteVolatile(Object var1, long var2); + +public native void putByteVolatile(Object var1, long var2, byte var4); + +public native short getShortVolatile(Object var1, long var2); + +public native void putShortVolatile(Object var1, long var2, short var4); + +public native char getCharVolatile(Object var1, long var2); + +public native void putCharVolatile(Object var1, long var2, char var4); + +public native long getLongVolatile(Object var1, long var2); + +public native void putLongVolatile(Object var1, long var2, long var4); + +public native float getFloatVolatile(Object var1, long var2); + +public native void putFloatVolatile(Object var1, long var2, float var4); + +public native double getDoubleVolatile(Object var1, long var2); + +public native void putDoubleVolatile(Object var1, long var2, double var4); + +#####线程 + +//释放当前阻塞的线程,该操作为线程不安全,因为不确定线程是否被销毁 +public native void unpark(Object var1); + +//阻塞当前线程,当发生情况时返回:1.调用unpark方法2.线程被中断3.时间过期4.spuriously +public native void park(boolean var1, long var2); + +//获取一段时间内,运行的任务队列分配到可用处理器的平均数(平常说的 CPU 使用率) +public native int getLoadAverage(double[] var1, int var2); + + + + + + + -- Gitee