diff --git a/.idea/misc.xml b/.idea/misc.xml
index 28a804d8932aba40f168fd757a74cb718a955a1a..74c8fa57e34b84e28aebd7f20c1c7e0355cf35af 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,4 +3,5 @@
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index aee8ccae86726e88b14f7c04c74e0ff00d325433..fbc77d681b5353ef3515234ea96e41556c2afb93 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,8 +2,13 @@
+
+
+
+
+
@@ -12,9 +17,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </code>
+
+
+
+
+
true
@@ -37,7 +134,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -50,7 +221,8 @@
-
+
+
@@ -63,11 +235,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -100,6 +285,7 @@
+
1575879326719
@@ -164,9 +350,54 @@
1580545769184
-
+
+ 1583661003613
+
+
+
+ 1583661003613
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -179,7 +410,8 @@
-
+
+
@@ -199,6 +431,259 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git "a/second/week_02/73/AtomicInteger\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/second/week_02/73/AtomicInteger\346\272\220\347\240\201\345\210\206\346\236\220.md"
new file mode 100644
index 0000000000000000000000000000000000000000..e5514b60f7fe453096d4c1b6d64c4e2b70226b13
--- /dev/null
+++ "b/second/week_02/73/AtomicInteger\346\272\220\347\240\201\345\210\206\346\236\220.md"
@@ -0,0 +1,96 @@
+## 关于AtomicInteger的随笔
+
+
+### 属性
+
+```java
+// 获取Unsafe实例
+private static final Unsafe unsafe = Unsafe.getUnsafe();
+// 标识value字段的偏移量,用来寻找
+private static final long valueOffset;
+// 静态代码块,通过unsafe获取value的偏移量
+static {
+ try {
+ valueOffset = unsafe.objectFieldOffset
+ (AtomicInteger.class.getDeclaredField("value"));
+ } catch (Exception ex) { throw new Error(ex); }
+}
+
+// 存储int类型值的地方,使用volatile修饰
+private volatile int value;
+```
+
+(1)使用int类型的value存储值,且使用volatile修饰,volatile主要是保证可见性,即一个线程修改对另一个线程立即可见,主要的实现原理是内存屏障,这里不展开来讲,有兴趣的可以自行查阅相关资料。
+
+(2)调用Unsafe的objectFieldOffset()方法获取value字段在类中的偏移量,用于后面CAS操作时使用。
+
+### 方法
+
+#### 构造方法和没有使用cas的get和set方法
+
+```java
+ public AtomicInteger(int initialValue) {
+ value = initialValue;
+ }
+
+ public AtomicInteger() {
+ }
+
+ public final int get() {
+ return value;
+ }
+
+ public final void set(int newValue) {
+ value = newValue;
+ }
+```
+
+#### 通过Unsafe实现的set方法
+
+```java
+ // 调用putOrderedInt方法,有序写入,不保证原子性
+ public final void lazySet(int newValue) {
+ unsafe.putOrderedInt(this, valueOffset, newValue);
+ }
+ // 最终通过CAS方法赋值
+ public final int getAndSet(int newValue) {
+ return unsafe.getAndSetInt(this, valueOffset, newValue);
+ }
+ // 直接调用
+ public final boolean compareAndSet(int expect, int update) {
+ return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
+ }
+ // 没看出来和上一个语句的差别
+ public final boolean weakCompareAndSet(int expect, int update) {
+ return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
+ }
+```
+
+#### 自增自减以及加减的原子操作方法
+
+```java
+ // 自增1,调用unsafe的getAndAddInt方法,而unsafe中这个方法是调用CAS方法完成。返回未增加1时的值
+ public final int getAndIncrement() {
+ return unsafe.getAndAddInt(this, valueOffset, 1);
+ }
+ // 自减1,同上
+ public final int getAndDecrement() {
+ return unsafe.getAndAddInt(this, valueOffset, -1);
+ }
+ // 加上给定值,同上
+ public final int getAndAdd(int delta) {
+ return unsafe.getAndAddInt(this, valueOffset, delta);
+ }
+ // 自增1,返回加1后的值
+ public final int incrementAndGet() {
+ return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
+ }
+ // 自减1,返回减1后的值
+ public final int decrementAndGet() {
+ return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
+ }
+ // 加上一个值,返回操作后的值。
+ public final int addAndGet(int delta) {
+ return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
+ }
+```
diff --git "a/second/week_02/73/AtomicStampedReference\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/second/week_02/73/AtomicStampedReference\346\272\220\347\240\201\345\210\206\346\236\220.md"
new file mode 100644
index 0000000000000000000000000000000000000000..cf26a79c4361fb9bec2a167fc5805ec5ee47105a
--- /dev/null
+++ "b/second/week_02/73/AtomicStampedReference\346\272\220\347\240\201\345\210\206\346\236\220.md"
@@ -0,0 +1,92 @@
+## 关于AtomicStampedReference的随笔
+
+
+### 属性
+
+```java
+ // 内部定义类Pair,两个属性,reference,stamp,将元素值和版本号绑定在一起
+ 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);
+ }
+ }
+ // 声明一个Pair类型变量,在上面已经定义
+ private volatile Pair pair;
+ // 获取Unsafe实例
+ private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
+ // 获取pair变量的偏移量,方便寻址
+ private static final long pairOffset =
+ objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
+```
+
+### 方法
+
+#### 构造方法
+
+```java
+ public AtomicStampedReference(V initialRef, int initialStamp) {
+ pair = Pair.of(initialRef, initialStamp);
+ }
+```
+
+构造方法只有一个,需要传入两个参数,一个是初始值,一个是初始版本号。
+
+#### 普通get/set方法
+
+```java
+ // 返回值
+ public V getReference() {
+ return pair.reference;
+ }
+ // 返回版本号
+ public int getStamp() {
+ return pair.stamp;
+ }
+ // 返回值,参数接收版本号
+ public V get(int[] stampHolder) {
+ Pair pair = this.pair;
+ stampHolder[0] = pair.stamp;
+ return pair.reference;
+ }
+
+ public void set(V newReference, int newStamp) {
+ Pair current = pair;
+ if (newReference != current.reference || newStamp != current.stamp)
+ this.pair = Pair.of(newReference, newStamp);
+ }
+```
+
+#### compareAndSet()方法
+
+```java
+ public boolean compareAndSet(V expectedReference,
+ V newReference,
+ int expectedStamp,
+ int newStamp) {
+ // 获取当前pair
+ Pair current = pair;
+ return
+ // 判断当前reference有没有变化
+ expectedReference == current.reference &&
+ // 判断版本号有没有变化
+ expectedStamp == current.stamp &&
+ // 判断要更改的reference和版本号是否与当前的pair一致,是则不用更改,否则更新
+ ((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);
+ }
+```
+
+调用了Unsafe类中的CAS方法,实现了原子操作,并通过版本号的引入克服了ABA问题。
+
+
diff --git "a/second/week_02/73/Unsafe\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/second/week_02/73/Unsafe\346\272\220\347\240\201\345\210\206\346\236\220.md"
new file mode 100644
index 0000000000000000000000000000000000000000..c4e7844724b254ec21fb02db627a530eef96dbab
--- /dev/null
+++ "b/second/week_02/73/Unsafe\346\272\220\347\240\201\345\210\206\346\236\220.md"
@@ -0,0 +1,209 @@
+##关于Unsafe的随笔
+
+> Unsafe为我们提供了访问底层的机制,这种机制仅供java核心类库使用,而不应该被普通用户使用。
+
+> java是没有指针的,默认是由JVM进行内存的分配与垃圾回收,这时候就需要Unsafe类。UnSafe提供了硬件级别的原子操作,Unsafe类通过JNI的方式访问本地的C++实现库从而使java具有了直接操作内存空间的能力,但这同时也带来了一定的问题,如果不合理地使用Unsafe类操作内存空间,可能导致内存泄漏
+
+
+##1 获取Unsafe
+```Java
+@CallerSensitive
+public static Unsafe getUnsafe() {
+ Class> caller = Reflection.getCallerClass();
+ if (!VM.isSystemDomainLoader(caller.getClassLoader()))
+ throw new SecurityException("Unsafe");
+ return theUnsafe;
+}
+```
+#### Unsafe提供了一个静态方法getUnsafe()用于获取它的实例对象,但直接调用会抛出SecurityException异常,这是因为Unsafe只提供给Java核心类使用,那么可以通过反射获取它的实例:
+```Java
+public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException{
+ Field field = Unsafe.class.getDeclaredField("theUnsafe");//getField只能获取public属性
+ field.setAccessible(true);//关闭访问安全检查开关
+ Unsafe unsafe = (Unsafe) field.get(null);
+ }
+```
+
+##2 使用Unsafe实例化一个类
+```java
+ //Unsafe通过一个native方法实现实例化一个类, 但是只会分配内存, 并不会调用该类的构造方法
+ public native Object allocateInstance(Class> var1) throws InstantiationException;
+```
+
+##3 修改私有字段的值
+使用Unsafe的putXXX()方法,我们可以修改任意私有字段的值。
+```java
+public class UnsafeTest {
+ public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+ //获取unsafe实例
+ Field f = Unsafe.class.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ Unsafe unsafe = (Unsafe) f.get(null);
+ //获取user实例, 并指定age = 19
+ User user = new User(19);
+ System.out.println(user.getAge());//19
+ //通过反射获取User.class的age属性
+ Field age = user.getClass().getDeclaredField("age");
+ //调用unsafe.putInt, 参数为: 指定对象, 偏移量, 修改后的值
+ //putInt方法通过获取user对象的起始地址, 加上objectFieldOffset()获取到的偏移值得到对应的update地址, 然后将20写入对应的update地址
+ unsafe.putInt(user, unsafe.objectFieldOffset(age), 20);
+ System.out.println(user.getAge());//20
+ }
+}
+
+class User {
+ private int age;
+
+ public User(int age) {
+ this.age = age;
+ }
+
+ public int getAge() {
+ return age;
+ }
+}
+```
+
+##4 Unsafe类
+
+ ```Java
+//下面是sun.misc.Unsafe.java类源码
+package sun.misc;
+import java.lang.reflect.Field;
+/***
+ * 这个类提供了一个更底层的操作并且应该在受信任的代码中使用。可以通过内存地址
+ * 存取fields,如果给出的内存地址是无效的那么会有一个不确定的运行表现。
+ */
+public class Unsafe
+{
+ private static Unsafe unsafe = new Unsafe();
+//使用私有默认构造器防止创建多个实例
+ private Unsafe()
+ {
+ }
+ /***
+ * 获取Unsafe的单例,这个方法调用应该防止在不可信的代码中实例,
+ * 因为unsafe类提供了一个低级别的操作,例如直接内存存取。
+ * 如果安全管理器不存在或者禁止访问系统属性
+ */
+ public static Unsafe getUnsafe()
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPropertiesAccess();
+ return unsafe;
+ }
+
+ /***
+ * 返回指定静态field的内存地址偏移量,在这个类的其他方法中这个值只是被用作一个访问
+ * 特定field的一个方式。这个值对于 给定的field是唯一的,并且后续对该方法的调用都应该
+ * 返回相同的值。
+ */
+ public native long objectFieldOffset(Field field);
+ /***
+ * 在obj的offset位置比较integer field和期望的值,如果相同则更新。这个方法
+ * 的操作应该是原子的,因此提供了一种不可中断的方式更新integer field。
+ */
+ public native boolean compareAndSwapInt(Object obj, long offset,
+ int expect, int update);
+ /***
+ * 在obj的offset位置比较long field和期望的值,如果相同则更新。这个方法
+ * 的操作应该是原子的,因此提供了一种不可中断的方式更新long field。
+ */
+ public native boolean compareAndSwapLong(Object obj, long offset,
+ long expect, long update);
+ /***
+ * 在obj的offset位置比较object field和期望的值,如果相同则更新。这个方法
+ * 的操作应该是原子的,因此提供了一种不可中断的方式更新object field。
+ */
+ public native boolean compareAndSwapObject(Object obj, long offset,
+ Object expect, Object update);
+ /***
+ * 设置obj对象中offset偏移地址对应的整型field的值为指定值。这是一个有序或者
+ * 有延迟的putIntVolatile方法,并且不保证值的改变被其他线程立
+ * 即看到。只有在field被volatile修饰并且期望被意外修改的时候
+ * 使用才有用。
+ */
+ public native void putOrderedInt(Object obj, long offset, int value);
+ /***
+ * 设置obj对象中offset偏移地址对应的long型field的值为指定值。这是一个有序或者
+ * 有延迟的putLongVolatile方法,并且不保证值的改变被其他线程立
+ * 即看到。只有在field被volatile修饰并且期望被意外修改的时候
+ * 使用才有用。
+ */
+ public native void putOrderedLong(Object obj, long offset, long value);
+ /***
+ * 设置obj对象中offset偏移地址对应的object型field的值为指定值。这是一个有序或者
+ * 有延迟的putObjectVolatile方法,并且不保证值的改变被其他线程立
+ * 即看到。只有在field被volatile修饰并且期望被意外修改的时候
+ * 使用才有用。
+ */
+ public native void putOrderedObject(Object obj, long offset, Object value);
+ /***
+ * 设置obj对象中offset偏移地址对应的整型field的值为指定值。支持volatile store语义
+ */
+ public native void putIntVolatile(Object obj, long offset, int value);
+ /***
+ * 获取obj对象中offset偏移地址对应的整型field的值,支持volatile load语义。
+ */
+ public native int getIntVolatile(Object obj, long offset);
+ /***
+ * 设置obj对象中offset偏移地址对应的long型field的值为指定值。支持volatile store语义
+ */
+ public native void putLongVolatile(Object obj, long offset, long value);
+ /***
+ * 设置obj对象中offset偏移地址对应的long型field的值为指定值。
+ */
+ public native void putLong(Object obj, long offset, long value);
+ /***
+ * 获取obj对象中offset偏移地址对应的long型field的值,支持volatile load语义。
+ */
+ public native long getLongVolatile(Object obj, long offset);
+ /***
+ * 获取obj对象中offset偏移地址对应的long型field的值
+ */
+ public native long getLong(Object obj, long offset);
+ /***
+ * 设置obj对象中offset偏移地址对应的object型field的值为指定值。支持volatile store语义
+ */
+ public native void putObjectVolatile(Object obj, long offset, Object value);
+ /***
+ * 设置obj对象中offset偏移地址对应的object型field的值为指定值。
+ */
+ public native void putObject(Object obj, long offset, Object value);
+ /***
+ * 获取obj对象中offset偏移地址对应的object型field的值,支持volatile load语义。
+ */
+ public native Object getObjectVolatile(Object obj, long offset);
+ /***
+ * 获取给定数组中第一个元素的偏移地址。
+ * 为了存取数组中的元素,这个偏移地址与arrayIndexScale
+ * 方法的非0返回值一起被使用。
+ */
+ public native int arrayBaseOffset(Class arrayClass);
+ /***
+ * 获取用户给定数组寻址的换算因子.一个合适的换算因子不能返回的时候(例如:基本类型),
+ * 返回0.这个返回值能够与arrayBaseOffset
+ * 一起使用去存取这个数组class中的元素
+ */
+ public native int arrayIndexScale(Class arrayClass);
+
+ /***
+ * 释放被park创建的在一个线程上的阻塞.这个
+ * 方法也可以被使用来终止一个先前调用park导致的阻塞.
+ * 这个操作操作时不安全的,因此线程必须保证是活的.这是java代码不是native代码。
+ */
+ public native void unpark(Thread thread);
+ /***
+ * 阻塞一个线程直到unpark出现、线程
+ * 被中断或者timeout时间到期。如果一个unpark调用已经出现了,
+ * 这里只计数。timeout为0表示永不过期.当isAbsolute为true时,
+ * timeout是相对于新纪元之后的毫秒。否则这个值就是超时前的纳秒数。这个方法执行时
+ * 也可能不合理地返回(没有具体原因)
+ */
+ public native void park(boolean isAbsolute, long time);
+}
+```
+
+
+