diff --git a/week_02/28/AtomicInteger.md b/week_02/28/AtomicInteger.md new file mode 100644 index 0000000000000000000000000000000000000000..8c67db65d72a8d3a3fce835ddc98d0109e0a3608 --- /dev/null +++ b/week_02/28/AtomicInteger.md @@ -0,0 +1,159 @@ +# AtomicInteger 源码分析 + +## AtomicInteger是juc(java.util.concurrent)包下提供的一个可以原子性操作Integer对象的类。通过它,我们可以很方便的对Integer进行线程安全的加、减、改值等操作。其原理是使用的CAS无锁算法。 + +初始化Unsafe 和内存偏移量 + +```java + +private static final long serialVersionUID = 6214790243416807050L; + +// setup to use Unsafe.compareAndSwapInt for updates +//JAVA实现CAS算法的类,整个类有关线程安全的操作,都是借助它来实现。 +private static final Unsafe unsafe = Unsafe.getUnsafe(); +//变量value的内存首地址的偏移量。 +private static final long valueOffset; +//静态代码块,在类加载时运行 +static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicInteger.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } +} + +private volatile int value;// 初始化值 +``` + +其他实现方法 + +```java +    /** +     * 创建一个AtomicInteger,初始值value为initialValue +     */ +    public AtomicInteger(int initialValue) { +        value = initialValue; +    } + +    /** +     * 创建一个AtomicInteger,初始值value为0 +     */ +    public AtomicInteger() { +    } + +    /** +     * 返回value +     */ +    public final int get() { +        return value; +    } + +    /** +     * 为value设值(基于value),而其他操作是基于旧值<--get() +     */ +    public final void set(int newValue) { +        value = newValue; +    } + +    public final boolean compareAndSet(int expect, int update) { +        return unsafe.compareAndSwapInt(this, valueOffset, expect, update); +    } +     +    /** +     * 基于CAS为旧值设定新值,采用无限循环,直到设置成功为止 +     *  +     * @return 返回旧值 +     */ +    public final int getAndSet(int newValue) { +        for (;;) { +            int current = get();// 获取当前值(旧值) +            if (compareAndSet(current, newValue))// CAS新值替代旧值 +                return current;// 返回旧值 +        } +    } + +    /** +     * 当前值+1,采用无限循环,直到+1成功为止 +     * @return the previous value 返回旧值 +     */ +    public final int getAndIncrement() { +        for (;;) { +            int current = get();//获取当前值 +            int next = current + 1;//当前值+1 +            if (compareAndSet(current, next))//基于CAS赋值 +                return current; +        } +    } + +    /** +     * 当前值-1,采用无限循环,直到-1成功为止  +     * @return the previous value 返回旧值 +     */ +    public final int getAndDecrement() { +        for (;;) { +            int current = get(); +            int next = current - 1; +            if (compareAndSet(current, next)) +                return current; +        } +    } + +    /** +     * 当前值+delta,采用无限循环,直到+delta成功为止  +     * @return the previous value  返回旧值 +     */ +    public final int getAndAdd(int delta) { +        for (;;) { +            int current = get(); +            int next = current + delta; +            if (compareAndSet(current, next)) +                return current; +        } +    } + +    /** +     * 当前值+1, 采用无限循环,直到+1成功为止 +     * @return the updated value 返回新值 +     */ +    public final int incrementAndGet() { +        for (;;) { +            int current = get(); +            int next = current + 1; +            if (compareAndSet(current, next)) +                return next;//返回新值 +        } +    } + +    /** +     * 当前值-1, 采用无限循环,直到-1成功为止  +     * @return the updated value 返回新值 +     */ +    public final int decrementAndGet() { +        for (;;) { +            int current = get(); +            int next = current - 1; +            if (compareAndSet(current, next)) +                return next;//返回新值 +        } +    } + +    /** +     * 当前值+delta,采用无限循环,直到+delta成功为止   +     * @return the updated value 返回新值 +     */ +    public final int addAndGet(int delta) { +        for (;;) { +            int current = get(); +            int next = current + delta; +            if (compareAndSet(current, next)) +                return next;//返回新值 +        } +    } + +    /** +     * 获取当前值 +     */ +    public int intValue() { +        return get(); +    } + +``` \ No newline at end of file diff --git a/week_02/28/AtomicStampedReference.md b/week_02/28/AtomicStampedReference.md new file mode 100644 index 0000000000000000000000000000000000000000..34eb08dbb097b19dd7f615f385da52c7f4e536f4 --- /dev/null +++ b/week_02/28/AtomicStampedReference.md @@ -0,0 +1,52 @@ +# AtomicStampedReference 源码分析 + +## AtomicStampedReference主要使用来解决ABA问题的 +## 所谓ABA问题指的就是在A线程进行cas操作时,首先读取了变量的值为0,然后时间片用完,线程B通过cas成功将变量从0更改为1,然后又通过cas将变量从1更改为0,线程B时间片用完,线程A获得时间片,此时再读取变量的值仍然为0,那么线程A就判断变量没有改变,即没有线程对该变量操作,接着线程A就修改变量的值 +## 解决方法就是另外使用一个版本号,在判断变量是否修改时,不光要判断变量的值是否改变,还需要判断版本号是否改变,只有这两个都没有改变,我们才任务变量没有被其他线程改变 + +## 属性 + +```java +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); + } +} +private volatile Pair pair; + +``` + +## 修改 + +```java +public boolean compareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + Pair current = pair; + // 当前引用和期望的引用相同,版本号也一致 + // 代表没有其他线程修改变量 + // 接下来尝试set + // 如果新的引用和现有引用相同并且新的版本号和现有版本号也相同,那么就不需要再set了 + // 如果不同,那么就尝试使用cas修改内存中的变量值 + 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) { + return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); +} + +``` \ No newline at end of file diff --git a/week_02/28/LongAdder.md b/week_02/28/LongAdder.md new file mode 100644 index 0000000000000000000000000000000000000000..ac428d00c626d95a938c659edd8080e421442912 --- /dev/null +++ b/week_02/28/LongAdder.md @@ -0,0 +1,53 @@ +# LongAdder 源码分析 + +## LongAdder类与AtomicLong类的区别在于高并发时前者将对单一变量的CAS操作分散为对数组cells中多个元素的CAS操作,取值时进行求和;而在并发较低时仅对base变量进行CAS操作,与AtomicLong类原理相同。 + +## LongAdder的成员变量 + +```java +// CPU的数量 +static final int NCPU = Runtime.getRuntime().availableProcessors(); +// Cell对象的数组,长度一般是2的指数 +transient volatile Cell[] cells; +// 基础value值,当并发较低时,只累加该值 +transient volatile long base; +// 创建或者扩容Cells数组时使用的自旋锁变量 +transient volatile int cellsBusy; + +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); + } +} +``` + +## Add操作 + +```java +public void add(long x) { + Cell[] as; long b, v; int m; Cell a; + // 当cells数组为null时,会进行第一次cas操作尝试。 + 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))) + // 当cells数组不为null,并且通过getProbe() & m + // 定位的Cell对象不为null时进行第二次CAS操作。 + // 如果执行不成功,则进入longAccumulate函数。 + longAccumulate(x, null, uncontended); + } +} + +``` + +## base 操作方法,并发高时,此方法失败率增高 + +```java + +final boolean casBase(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, BASE, cmp, val); +} +``` \ No newline at end of file diff --git a/week_02/28/Unsafe.md b/week_02/28/Unsafe.md new file mode 100644 index 0000000000000000000000000000000000000000..a779ec6c5bf5246431e80f62f07eb8aca725ec31 --- /dev/null +++ b/week_02/28/Unsafe.md @@ -0,0 +1,113 @@ +# Unsafe 源码分析 + +## native 方法调用c++ 实现低级(native硬件级别的原子操作)、不安全的操作集合 +## C++ 方法列表 + +```java +//扩充内存 +public native long reallocateMemory(long address, long bytes); + +//分配内存 +public native long allocateMemory(long bytes); + +//释放内存 +public native void freeMemory(long address); + +//在给定的内存块中设置值 +public native void setMemory(Object o, long offset, long bytes, byte value); + +//从一个内存块拷贝到另一个内存块 +public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); + +//获取值,不管java的访问限制,其他有类似的getInt,getDouble,getLong,getChar等等 +public native Object getObject(Object o, long offset); + +//设置值,不管java的访问限制,其他有类似的putInt,putDouble,putLong,putChar等等 +public native void putObject(Object o, long offset); + +//从一个给定的内存地址获取本地指针,如果不是allocateMemory方法的,结果将不确定 +public native long getAddress(long address); + +//存储一个本地指针到一个给定的内存地址,如果地址不是allocateMemory方法的,结果将不确定 +public native void putAddress(long address, long x); + +//该方法返回给定field的内存地址偏移量,这个值对于给定的filed是唯一的且是固定不变的 +public native long staticFieldOffset(Field f); + +//报告一个给定的字段的位置,不管这个字段是private,public还是保护类型,和staticFieldBase结合使用 +public native long objectFieldOffset(Field f); + +//获取一个给定字段的位置 +public native Object staticFieldBase(Field f); + +//确保给定class被初始化,这往往需要结合基类的静态域(field) +public native void ensureClassInitialized(Class c); + +//可以获取数组第一个元素的偏移地址 +public native int arrayBaseOffset(Class arrayClass); + +//可以获取数组的转换因子,也就是数组中元素的增量地址。将arrayBaseOffset与arrayIndexScale配合使用, 可以定位数组中每个元素在内存中的位置 +public native int arrayIndexScale(Class arrayClass); + +//获取本机内存的页数,这个值永远都是2的幂次方 +public native int pageSize(); + +//告诉虚拟机定义了一个没有安全检查的类,默认情况下这个类加载器和保护域来着调用者类 +public native Class defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain); + +//定义一个类,但是不让它知道类加载器和系统字典 +public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches); + +//锁定对象,必须是没有被锁的 +public native void monitorEnter(Object o); + +//解锁对象 +public native void monitorExit(Object o); + +//试图锁定对象,返回true或false是否锁定成功,如果锁定,必须用monitorExit解锁 +public native boolean tryMonitorEnter(Object o); + +//引发异常,没有通知 +public native void throwException(Throwable ee); + +//CAS,如果对象偏移量上的值=期待值,更新为x,返回true.否则false.类似的有compareAndSwapInt,compareAndSwapLong,compareAndSwapBoolean,compareAndSwapChar等等。 +public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); + +// 该方法获取对象中offset偏移地址对应的整型field的值,支持volatile load语义。类似的方法有getIntVolatile,getBooleanVolatile等等 +public native Object getObjectVolatile(Object o, long offset); + +//线程调用该方法,线程将一直阻塞直到超时,或者是中断条件出现。 +public native void park(boolean isAbsolute, long time); + +//终止挂起的线程,恢复正常.java.util.concurrent包中挂起操作都是在LockSupport类实现的,也正是使用这两个方法 +public native void unpark(Object thread); + +//获取系统在不同时间系统的负载情况 +public native int getLoadAverage(double[] loadavg, int nelems); + +//创建一个类的实例,不需要调用它的构造函数、初使化代码、各种JVM安全检查以及其它的一些底层的东西。即使构造函数是私有,我们也可以通过这个方法创建它的实例,对于单例模式,简直是噩梦,哈哈 +public native Object allocateInstance(Class cls) throws InstantiationException; +``` + +原子CAS操作 + +```java +/** + * Atomically exchanges the given reference value with the current + * reference value of a field or array element within the given + * object o at the given offset. + * + * @param o object/array to update the field/element in + * @param offset field/element offset + * @param newValue new value + * @return the previous value + * @since 1.8 + */ +public final Object getAndSetObject(Object o, long offset, Object newValue) { + Object v; + do { + v = getObjectVolatile(o, offset);//获取对象内存地址偏移量上的数值v + } while (!compareAndSwapObject(o, offset, v, newValue));//如果现在还是v,设置为newValue,否则返回false,!false=true,一直循环直到等于v退出循环返回v. + return v; +} +``` \ No newline at end of file