From ba966e11e7f294d7ebed9a3dde20e8bf614d5042 Mon Sep 17 00:00:00 2001 From: webflyer1981 <723726786@qq.com> Date: Tue, 24 Dec 2019 21:10:03 +0800 Subject: [PATCH] 055-week2 --- week_02/55/AtomicInteger-55.md | 63 +++++++++++++++ week_02/55/AtomicStampedReference-55.md | 101 ++++++++++++++++++++++++ week_02/55/Unsafe-55.md | 55 +++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 week_02/55/AtomicInteger-55.md create mode 100644 week_02/55/AtomicStampedReference-55.md create mode 100644 week_02/55/Unsafe-55.md diff --git a/week_02/55/AtomicInteger-55.md b/week_02/55/AtomicInteger-55.md new file mode 100644 index 0000000..90da6e7 --- /dev/null +++ b/week_02/55/AtomicInteger-55.md @@ -0,0 +1,63 @@ +AtomicInteger源码剖析 +private static final Unsafe unsafe = Unsafe.getUnsafe();//调用指针类Unsafe +private static final long valueOffset;//变量value的内存偏移量 + +static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicInteger.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } +} + +private volatile int value;//volatile修饰的int变量value +  +public AtomicInteger(int initialValue) {//带参数的构造函数 + value = initialValue; +} + +public AtomicInteger() {//不带参数的构造函数 +} +         +public final int get() {//获取当前最新值 + return value; +} + + +public final void set(int newValue) {//设置当前值 + value = newValue; +} +public final void lazySet(int newValue) {//最终把值设置为newValue,使用该方法后,其他线程在一段时间内还会获取到旧值 + unsafe.putOrderedInt(this, valueOffset, newValue); +} + + +public final int getAndSet(int newValue) {//设置新值并返回旧值 + return unsafe.getAndSetInt(this, valueOffset, newValue); +} +public final boolean compareAndSet(int expect, int update) {//如果当前值为expect,则设置为update + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); +} +public final int getAndIncrement() {//当前值加1返回旧值 + return unsafe.getAndAddInt(this, valueOffset, 1); +} + + +public final int getAndDecrement() {//当前值减1返回旧值 + return unsafe.getAndAddInt(this, valueOffset, -1); +} + + +public final int getAndAdd(int delta) {//当前值增加delta,返回旧值 + return unsafe.getAndAddInt(this, valueOffset, delta); +} + + +public final int incrementAndGet() {//当前值增加1返回新值 + return unsafe.getAndAddInt(this, valueOffset, 1) + 1; +} + + +public final int decrementAndGet() {//当前值减1,返回新值 + return unsafe.getAndAddInt(this, valueOffset, -1) - 1; +} + diff --git a/week_02/55/AtomicStampedReference-55.md b/week_02/55/AtomicStampedReference-55.md new file mode 100644 index 0000000..75fc7bc --- /dev/null +++ b/week_02/55/AtomicStampedReference-55.md @@ -0,0 +1,101 @@ +CAS +cas????? +1.??? +2.??? +3.??? +volatile?????,????? +CAS??,???cpu???????,??????,????????????????????\ +cas????ABA?? +???ABA?? +??????????,??????????????,????????????fail??,???????????? +t1 t2 +A???????A->B->A +A->C +?????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????ABA????? +??????????????????version????? +???????????AtomicStampedReference?????? +public class AtomicStampedReferenceTest { + + private static AtomicStampedReference atomic = new AtomicStampedReference<>(100,0); + + public static void main(String[] args) { + new Thread(()->{ + try { + TimeUnit.SECONDS.sleep(1); + //?????,???stamp??? version ???1 ???????????1?.?????0?????? + boolean sucess = atomic.compareAndSet(100,101,atomic.getStamp(),atomic.getStamp()+1); + System.out.println(sucess); + sucess = atomic.compareAndSet(101,100,atomic.getStamp(),atomic.getStamp()+1); + System.out.println(sucess); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + + + new Thread(()->{ + try { + int stamp = atomic.getStamp(); + System.out.println("before: "+stamp);//??????stamp?1 + TimeUnit.SECONDS.sleep(2); + int stamp1 = atomic.getStamp(); + System.out.println("?????? stamp "+ stamp1);//????????stamp????2 ? + //?????,???stamp??? version ???1 ???????????1?.?????0?????? + boolean b = atomic.compareAndSet(100, 101, stamp, stamp + 1); + System.out.println("2??= "+b); + atomic.compareAndSet(101,100,stamp,stamp+1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + + } +} +??: +?=copy??? ??????,??????????????,??????, +????compareAndSet ??,?????????????,??????????????? + 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; + + /** + * 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.of(initialRef, initialStamp); + } + +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) || + casPair(current, Pair.of(newReference, newStamp))); +} + + diff --git a/week_02/55/Unsafe-55.md b/week_02/55/Unsafe-55.md new file mode 100644 index 0000000..0cb140f --- /dev/null +++ b/week_02/55/Unsafe-55.md @@ -0,0 +1,55 @@ +Unsafe中一共有82个public native修饰的方法,还有几十个基于这82个public native方法的其他方法。这些方法大体可以归结为以下几类: +(1)初始化操作 +(2)操作对象属性 +(3)操作数组元素 +(4)线程挂起和回复 +(5)CAS机制 +下面我们对这些方法尽进行一个大致的分析。 +1、初始化 + +在这里我们看到Unsafe的初始化方法主要是通过getUnsafe方法的单例模式实现的,调用JVM本地方法registerNatives()和sun.reflect.Reflection,通过Reflection的getCallerClass判断当前调用的类是否是主类加载器(BootStrap classLoader)加载的,否则的话抛出一个SecurityException。这也证明了一个问题,那就是只有由主类加载器(BootStrap classLoader)加载的类才能调用这个类中的方法。 +2、操作属性方法 +(1)public native Object getObject(Object o, long offset); +通过给定的Java变量获取引用值。这里实际上是获取一个Java对象o中,获取偏移地址为offset的属性的值,此方法可以突破修饰符的抑制,也就是无视private、protected和default修饰符。类似的方法有getInt、getDouble等等。同理还有putObject方法。 +(2)public native Object getObjectVolatile(Object o, long offset); +强制从主存中获取属性值。类似的方法有getIntVolatile、getDoubleVolatile等等。同理还有putObjectVolatile。 +(3)public native void putOrderedObject(Object o, long offset, Object x); +设置o对象中offset偏移地址offset对应的Object型field的值为指定值x。这是一个有序或者有延迟的putObjectVolatile方法,并且不保证值的改变被其他线程立即看到。只有在field被volatile修饰并且期望被修改的时候使用才会生效。类似的方法有putOrderedInt和putOrderedLong。 +(4)public native long staticFieldOffset(Field f); +返回给定的静态属性在它的类的存储分配中的位置(偏移地址)。 +(5)public native long objectFieldOffset(Field f); +返回给定的非静态属性在它的类的存储分配中的位置(偏移地址)。 +(6)public native Object staticFieldBase(Field f); +返回给定的静态属性的位置,配合staticFieldOffset方法使用。 +3、操作数组 +(1)public native int arrayBaseOffset(Class arrayClass); +返回数组类型的第一个元素的偏移地址(基础偏移地址)。 +(2)public native int arrayIndexScale(Class arrayClass); +返回数组中元素与元素之间的偏移地址的增量。 +这两个方法配合使用就可以定位到任何一个元素的地址。 +4、内存管理 +(1)public native int addressSize(); +获取本地指针的大小(单位是byte),通常值为4或者8。常量ADDRESS_SIZE就是调用此方法。 +(2)public native int pageSize(); +获取本地内存的页数,此值为2的幂次方。 +(3)public native long allocateMemory(long bytes); +分配一块新的本地内存,通过bytes指定内存块的大小(单位是byte),返回新开辟的内存的地址。 +(4)public native long reallocateMemory(long address, long bytes); +通过指定的内存地址address重新调整本地内存块的大小,调整后的内存块大小通过bytes指定(单位为byte)。 +(5)public native void setMemory(Object o, long offset, long bytes, byte value); +将给定内存块中的所有字节设置为固定值(通常是0)。 +5、线程挂起和恢复 +(1)public native void unpark(Object thread); +释放被park创建的在一个线程上的阻塞。由于其不安全性,因此必须保证线程是存活的。 +(2)public native void park(boolean isAbsolute, long time);` +阻塞当前线程,一直等道unpark方法被调用。 +6、内存屏障 +(1)public native void loadFence(); +在该方法之前的所有读操作,一定在load屏障之前执行完成。 +(2)public native void storeFence(); +在该方法之前的所有写操作,一定在store屏障之前执行完成 +(3)public native void fullFence(); +在该方法之前的所有读写操作,一定在full屏障之前执行完成,这个内存屏障相当于上面两个(load屏障和store屏障)的合体功能。 +7、CAS机制 + + -- Gitee