泥土巢 - JUC包之原子变量 https://www.nituchao.com/category/juc-atomic/ JUC包之原子变量的相关探讨 Atomic原子变量概述 https://www.nituchao.com/juc-atomic/27.html 2017-04-25T16:15:00+08:00 Java原子变量的诞生源自一个简单的需求 —— 多个线程共享某个变量或者对象时,需要对修改和读取操作进行同步。同步包含两层含义:互斥访问可见性通常,多线程对临界资源的互斥访问通过对象锁(synchronized关键字)保证。对象锁是一种独占锁(悲观锁),会导致其它所有需要锁的线程挂起。而可见性则由volatile的内存语义保证。Java 1.5开始提供了原子变量和原子引用,这些类放置在java.util.concurrent下。大概可以归为4类:基本类型:AtomicInteger, AtomicLong, AtomicBoolean;数组类型:AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray;引用类型:AtomicReference, AtomicStampedReference, AtomicMarkableReference;对象的属性修改类型:AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater;Java原子变量的存在是为了对相应的数据进行原子操作。所谓的原子操作包含下面几层含义:操作过程不会被中断。操作过程不会被阻塞。修改结果被其他线程可见。 源码分析之AtomicReference https://www.nituchao.com/juc-atomic/25.html 2017-04-24T16:13:00+08:00 概述在原子变量相关类中,AtomicReference, AtomicStampedReference, AtomicMarkableReference三个类是对于引用类型的操作,其原理和用法类似。AtomicStampedReference是带了整型版本号(int stamp)的引用型原子变量,每次执行CAS操作时需要对比版本,如果版本满足要求,则操作成功,否则操作失败,用于防止CAS操作的ABA问题。AtomicMarkableReference则是带了布尔型标记位(Boolean mark)的引用型原子量,每次执行CAS操作是需要对比该标记位,如果标记满足要求,则操作成功,否则操作失败。Java原子变量的实现依赖于sun.misc.Unsafe的CAS操作和volatile的内存可见性语义。本文基于JDK1.7.0_67java version "1.7.0_67"__Java(TM) SE Runtime Environment (build 1.7.0_67-b01)Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)成员变量AtomicReference通过泛型T来声明成员值的类型,表示这是对引用类型的操作。// 成员变量unsafe是原子变量相关操作的基础 // 原子变量的修改操作最终有sun.misc.Unsafe类的CAS操作实现 private static final Unsafe unsafe = Unsafe.getUnsafe(); // 成员变量value的内存偏移值,在静态代码块中初始化 private static final long valueOffset; // 通过volatile关键字保证可见性,用于保存值 private volatile V value; static { try { valueOffset = unsafe.objectFieldOffset (AtomicReference.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }函数列表// 构造函数,初始化值为null public AtomicReference() // 构造函数,指定初始化值 public AtomicReference(V initialValue) // 以原子方式获取当前值 public final V get() // 以原子方式设置当前值为新的值newValue public final void set(V newValue) // 以原子方式设置当前值为新的值newValue // 优先保证修改操作,而不保证volatile的可见性语义 // 效率较高 public final void lazySet(V newValue) // 以原子方式设置当前值为update // 如果当前值等于except,则设置成功,返回true // 如果当前值不等于except,则设置失败,返回fase // 该过程不阻塞 public final boolean compareAndSet(V expect, V update) // 以原子方式设置当前值为update // 如果当前值等于except,则设置成功,返回true // 如果当前值不等于except,则设置失败,返回fase // 该过程不阻塞 // 该过程不保证volatile成员的happens-before语义顺序 public final boolean weakCompareAndSet(V expect, V update) // 以原子方式设置当前值为update // 返回更新前的值 public final V getAndSet(V newValue) // 返回当前值的string表达式 public String toString()重点函数分析set(V newValue)以原子方式设置当前值为newValue,因为set方法只是一个单操作的赋值语句,因此是原子的。加上volatile的内存可见性保证,Set是原子操作无疑。lazySet(V newValue)简单点说,lazySet优先保证数据的修改操作,而降低对可见性的要求。lazySet是使用Unsafe.putOrderedObject方法,这个方法在对低延迟代码是很有用的,它能够实现非堵塞的写入,这些写入不会被Java的JIT重新排序指令(instruction reordering),这样它使用快速的存储-存储(store-store) barrier, 而不是较慢的存储-加载(store-load) barrier, 后者总是用在volatile的写操作上,这种性能提升是有代价的,虽然便宜,也就是写后结果并不会被其他线程看到,甚至是自己的线程,通常是几纳秒后被其他线程看到,这个时间比较短,所以代价可以忍受。类似Unsafe.putOrderedObject还有unsafe.putOrderedLong等方法,unsafe.putOrderedLong比使用 volatile long要快3倍左右。compareAndSet(V expect,V update)以原子方式设置当前值为update。如果当前值等于expect,并设置成功,返回true。如果当前值不等于expect,则设置失败,返回false。该过程不阻塞。由于是使用了sun.misc.Unsafe的CAS操作实现,它是原子操作无疑。_set和compareAndSet都是原子操作,只是他们的目的不同,set只是单纯想设置一个新的值。而compareAndSet则是希望在满足一定条件的情况下(当前值等于except)再设置新的值。weakCompareAndSet(V expect,V update)以原子方式设置当前值为update。它的实现与compareAndSet完全一致。JDK文档中说,weakCompareAndSet在更新变量时并不创建任何happens-before顺序,因此即使要修改的值是volatile的,也不保证对该变量的读写操作的顺序(一般来讲,volatile的内存语义保证happens-before顺序)。参考:Java.Util.Concurrent.Atomic.AtomicMarkableReference Class 源码分析之AtomicStampedReference https://www.nituchao.com/juc-atomic/26.html 2017-04-19T16:14:00+08:00 概述在原子变量相关类中,AtomicReference, AtomicStampedReference, AtomicMarkableReference三个类是对于引用类型的操作,其原理和用法类似。AtomicStampedReference是带了整型版本号(int stamp)的引用型原子变量,每次执行CAS操作时需要对比版本,如果版本满足要求,则操作成功,否则操作失败,用于防止CAS操作的ABA问题。本文重点分析AtomicStampedReference。AtomicMarkableReference则是带了布尔型标记位(Boolean mark)的引用型原子量,每次执行CAS操作是需要对比该标记位,如果标记满足要求,则操作成功,否则操作失败。Java原子变量的实现依赖于sun.misc.Unsafe的CAS操作和volatile的内存可见性语义。本文基于JDK1.7.0_67java version "1.7.0_67"__Java(TM) SE Runtime Environment (build 1.7.0_67-b01)Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)内部类AtomicStampedReference是带整形版本号的原子引用类型,为了同时兼顾引用值和版本号,它定义了一个静态内部类Pair,AtomicStampedReference的相关操作都是对Pair内成员的操作。private static class Pair<T> { final T reference; final int stamp; private Pair(T reference, int stamp) { this.reference = reference; this.stamp = stamp; } static <T> Pair<T> of(T reference, int stamp) { return new Pair<T>(reference, stamp); } }成员变量AtomicStampedReference除了常规的sun.misc.Unsafe实例和pairOffset内存偏移量外,声明了一个volatile的Pair<T>成员,用于同时维护引用值和版本号。// 成员变量unsafe是原子变量相关操作的基础 // 原子变量的修改操作最终有sun.misc.Unsafe类的CAS操作实现 private static final sun.misc.Unsafe UNSAFE = Unsafe.getUnsafe(); // 成员变量value的内存偏移值 private static final long pairOffset = objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class); // 用volatile的内存语义保证可见性 // 保存引用值和版本号 private volatile Pair<V> pair; // 获取指定域的内存偏移量 static long objectFieldOffset(sun.misc.Unsafe UNSAFE, String field, Class<?> klazz) { try { return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); } catch (NoSuchFieldException e) { // Convert Exception to corresponding Error NoSuchFieldError error = new NoSuchFieldError(field); error.initCause(e); throw error; } }函数列表由于AtomicStampedReference要同时维护引用值和版本号,因此很多操作变得复杂。// 构造函数,初始化引用和版本号 public AtomicStampedReference(V initialRef, int initialStamp) // 以原子方式获取当前引用值 public V getReference() // 以原子方式获取当前版本号 public int getStamp() // 以原子方式获取当前引用值和版本号 public V get(int[] stampHolder) // 以原子的方式同时更新引用值和版本号 // 当期望引用值不等于当前引用值时,操作失败,返回false // 当期望版本号不等于当前版本号时,操作失败,返回false // 在期望引用值和期望版本号同时等于当前值的前提下 // 当新的引用值和新的版本号同时等于当前值时,不更新,直接返回true // 当新的引用值和新的版本号不同时等于当前值时,同时设置新的引用值和新的版本号,返回true // 该过程不保证volatile成员的happens-before语义顺序 public boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) // 以原子的方式同时更新引用值和版本号 // 当期望引用值不等于当前引用值时,操作失败,返回false // 当期望版本号不等于当前版本号时,操作失败,返回false // 在期望引用值和期望版本号同时等于当前值的前提下 // 当新的引用值和新的版本号同时等于当前值时,不更新,直接返回true // 当新的引用值和新的版本号不同时等于当前值时,同时设置新的引用值和新的版本号,返回true public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) // 以原子方式设置引用的当前值为新值newReference // 同时,以原子方式设置版本号的当前值为新值newStamp // 新引用值和新版本号只要有一个跟当前值不一样,就进行更新 public void set(V newReference, int newStamp) // 以原子方式设置版本号为新的值 // 前提:引用值保持不变 // 当期望的引用值与当前引用值不相同时,操作失败,返回fasle // 当期望的引用值与当前引用值相同时,操作成功,返回true public boolean attemptStamp(V expectedReference, int newStamp) // 使用`sun.misc.Unsafe`类原子地交换两个对象 private boolean casPair(Pair<V> cmp, Pair<V> val)重点函数分析AtomicStampedReferencepublic AtomicStampedReference(V initialRef, int initialStamp) { pair = Pair.of(initialRef, initialStamp); }构造函数,根据指定的引用值和版本号,构造一个Pair对象,并将该对象赋值给成员变量pair。由于成员变量pair被volatile修饰,并且这里只有一个单操作的赋值语句,因此是可以保证原子性的。getpublic V get(int[] stampHolder) { Pair<V> pair = this.pair; stampHolder[0] = pair.stamp; return pair.reference; }真个函数很有意思,同时获取引用值和版本号。由于Java程序只能有一个返回值,该函数通过一个数组参数int[] stampHolder来返回版本号,而通过return语句返回引用值。setpublic void set(V newReference, int newStamp) { Pair<V> current = pair; if (newReference != current.reference || newStamp != current.stamp) this.pair = Pair.of(newReference, newStamp); }只要新的引用值和新的版本号,有一个与当前值不一样的,就同时修改引用值和版本号。compareAndSetpublic boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { Pair<V> current = pair; return expectedReference == current.reference && expectedStamp == current.stamp && ((newReference == current.reference && newStamp == current.stamp) || casPair(current, Pair.of(newReference, newStamp))); }以原子的方式同时更新引用值和版本号。当期望引用值不等于当前引用值时,操作失败,返回false。当期望版本号不等于当前版本号时,操作失败,返回false。在期望引用值和期望版本号同时等于当前值的前提下,当新的引用值和新的版本号同时等于当前值时,不更新,直接返回true。由于要修改的内容与原内容完全一致,这种处理可以避免一次内存操作,效率较高。当新的引用值和新的版本号不同时等于当前值时,同时设置新的引用值和新的版本号,返回trueweakCompareAndSetpublic boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { return compareAndSet(expectedReference, newReference, expectedStamp, newStamp); }以原子的方式同时更新引用值和版本号。该是通过调用CompareAndSet实现的。JDK文档中说,weakCompareAndSet在更新变量时并不创建任何happens-before顺序,因此即使要修改的值是volatile的,也不保证对该变量的读写操作的顺序(一般来讲,volatile的内存语义保证happens-before顺序)。attemptStamppublic boolean attemptStamp(V expectedReference, int newStamp) { Pair<V> current = pair; return expectedReference == current.reference && (newStamp == current.stamp || casPair(current, Pair.of(expectedReference, newStamp))); }修改指定引用值的版本号。当期望的引用值与当前引用值不相同时,操作失败,返回fasle。当期望的引用值与当前引用值相同时,操作成功,返回true。casPairprivate boolean casPair(Pair<V> cmp, Pair<V> val) { return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); }使用sun.misc.Unsafe类原子地交换两个对象。 源码分析之AtomicMarkableReference https://www.nituchao.com/juc-atomic/24.html 2017-04-19T16:13:00+08:00 概述在原子变量相关类中,AtomicReference, AtomicStampedReference, AtomicMarkableReference三个类是对于引用类型的操作,其原理和用法类似。AtomicStampedReference是带了整型标记值(int stamp)的引用型原子变量,每次执行CAS操作时需要对比版本,如果版本满足要求,则操作成功,否则操作失败,用于防止CAS操作的ABA问题。AtomicMarkableReference则是带了布尔型标记位(Boolean mark)的引用型原子量,每次执行CAS操作是需要对比该标记位,如果标记满足要求,则操作成功,否则操作失败。本文重点分析AtomicMarkableReference。Java原子变量的实现依赖于sun.misc.Unsafe的CAS操作和volatile的内存可见性语义。本文基于JDK1.7.0_67java version "1.7.0__67"__Java(TM) SE Runtime Environment (build 1.7.0_67-b01)Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)内部类AtomicMarkableReference是带布尔型标记为的原子引用类型,为了同时兼顾引用值和标记位,它定义了一个静态内部类Pair,AtomicMarkableReference的相关操作都是对Pair内成员的操作。private static class Pair<T> { final T reference; final boolean mark; private Pair(T reference, boolean mark) { this.reference = reference; this.mark = mark; } static <T> Pair<T> of(T reference, int mark) { return new Pair<T>(reference, mark); } }成员变量AtomicMarkableReference除了常规的sun.misc.Unsafe实例和pairOffset内存偏移量外,声明了一个volatile的Pair<T>成员,用于同时维护引用值和标记值。// 成员变量unsafe是原子变量相关操作的基础 // 原子变量的修改操作最终有sun.misc.Unsafe类的CAS操作实现 private static final sun.misc.Unsafe UNSAFE = Unsafe.getUnsafe(); // 成员变量value的内存偏移值 private static final long pairOffset = objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class); // 用volatile的内存语义保证可见性 // 保存引用值和标记值 private volatile Pair<V> pair; // 获取指定域的内存偏移量 static long objectFieldOffset(sun.misc.Unsafe UNSAFE, String field, Class<?> klazz) { try { return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); } catch (NoSuchFieldException e) { // Convert Exception to corresponding Error NoSuchFieldError error = new NoSuchFieldError(field); error.initCause(e); throw error; } }函数列表由于AtomicMarkableReference要同时维护引用值和标记值,因此很多操作变得复杂。// 构造函数,初始化引用和标记值 public AtomicMarkableReference(V initialRef, boolean initialMark) // 以原子方式获取当前引用值 public V getReference() // 以原子方式获取当前标记值 public int isMarked() // 以原子方式获取当前引用值和标记值 public V get(boolean[] markHolder) // 以原子的方式同时更新引用值和标记值 // 当期望引用值不等于当前引用值时,操作失败,返回false // 当期望标记值不等于当前标记值时,操作失败,返回false // 在期望引用值和期望标记值同时等于当前值的前提下 // 当新的引用值和新的标记值同时等于当前值时,不更新,直接返回true // 当新的引用值和新的标记值不同时等于当前值时,同时设置新的引用值和新的标记值,返回true // 该过程不保证volatile成员的happens-before语义顺序 public boolean weakCompareAndSet(V expectedReference, V newReference, int expectedMark, int newMark) // 以原子的方式同时更新引用值和标记值 // 当期望引用值不等于当前引用值时,操作失败,返回false // 当期望标记值不等于当前标记值时,操作失败,返回false // 在期望引用值和期望标记值同时等于当前值的前提下 // 当新的引用值和新的标记值同时等于当前值时,不更新,直接返回true // 当新的引用值和新的标记值不同时等于当前值时,同时设置新的引用值和新的标记值,返回true public boolean compareAndSet(V expectedReference, V newReference, int expectedMark, int newMark) // 以原子方式设置引用的当前值为新值newReference // 同时,以原子方式设置标记值的当前值为新值newMark // 新引用值和新标记值只要有一个跟当前值不一样,就进行更新 public void set(V newReference, int newMark) // 以原子方式设置标记值为新的值 // 前提:引用值保持不变 // 当期望的引用值与当前引用值不相同时,操作失败,返回fasle // 当期望的引用值与当前引用值相同时,操作成功,返回true public boolean attemptMark(V expectedReference, int newMark) // 使用`sun.misc.Unsafe`类原子地交换两个对象 private boolean casPair(Pair<V> cmp, Pair<V> val)重点函数分析AtomicMarkableReferencepublic AtomicMarkableReference(V initialRef, int initialMark) { pair = Pair.of(initialRef, initialMark); }构造函数,根据指定的引用值和标记值,构造一个Pair对象,并将该对象赋值给成员变量pair。由于成员变量pair被volatile修饰,并且这里只有一个单操作的赋值语句,因此是可以保证原子性的。getpublic V get(int[] markHolder) { Pair<V> pair = this.pair; markHolder[0] = pair.markz; return pair.reference; }真个函数很有意思,同时获取引用值和标记值。由于Java程序只能有一个返回值,该函数通过一个数组参数int[] markHolder来返回标记值,而通过return语句返回引用值。setpublic void set(V newReference, int newMark) { Pair<V> current = pair; if (newReference != current.reference || newMark != current.mark) this.pair = Pair.of(newReference, newMark); }只要新的引用值和新的标记值,有一个与当前值不一样的,就同时修改引用值和标记值。compareAndSetpublic boolean compareAndSet(V expectedReference, V newReference, int expectedMark, int newMark) { Pair<V> current = pair; return expectedReference == current.reference && expectedMark == current.mark && ((newReference == current.reference && newMark == current.mark) || casPair(current, Pair.of(newReference, newMark))); }以原子的方式同时更新引用值和标记值。当期望引用值不等于当前引用值时,操作失败,返回false。当期望标记值不等于当前标记值时,操作失败,返回false。在期望引用值和期望标记值同时等于当前值的前提下,当新的引用值和新的标记值同时等于当前值时,不更新,直接返回true。由于要修改的内容与原内容完全一致,这种处理可以避免一次内存操作,效率较高。当新的引用值和新的标记值不同时等于当前值时,同时设置新的引用值和新的标记值,返回trueweakCompareAndSetpublic boolean weakCompareAndSet(V expectedReference, V newReference, int expectedMark, int newMark) { return compareAndSet(expectedReference, newReference, expectedMark, newMark); }以原子的方式同时更新引用值和标记值。该是通过调用CompareAndSet实现的。JDK文档中说,weakCompareAndSet在更新变量时并不创建任何happens-before顺序,因此即使要修改的值是volatile的,也不保证对该变量的读写操作的顺序(一般来讲,volatile的内存语义保证happens-before顺序)。attemptMarkpublic boolean attemptMark(V expectedReference, int newMark) { Pair<V> current = pair; return expectedReference == current.reference && (newMark == current.mark || casPair(current, Pair.of(expectedReference, newMark))); }修改指定引用值的标记值。当期望的引用值与当前引用值不相同时,操作失败,返回fasle。当期望的引用值与当前引用值相同时,操作成功,返回true。casPairprivate boolean casPair(Pair<V> cmp, Pair<V> val) { return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); }使用sun.misc.Unsafe类原子地交换两个对象。 源码分析之AtomicLongFieldUpdater https://www.nituchao.com/juc-atomic/23.html 2017-04-13T16:12:00+08:00 概述在原子变量相关类中,AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater三个类是用于原子地修改对象的成员属性,它们的原理和用法类似,区别在于对Integer,Long,Reference类型的成员属性进行修改。本文重点研究AtomicLongFieldUpdater。AtomicLongFieldUpdater的设计非常有意思。AtomicLongFieldUpdater本身是一个抽象类,只有一个受保护的构造函数,它本身不能被实例化。AtomicLongFieldUpdater有两个私有的静态内部类CASUpdater和LockedUpdater,它们都是AtomicLongFieldUpdater的子类。用户使用AtomicLongFieldUpdater的静态方法newUpdater实例化AtomicLongFieldUpdater子类对象,本质是上是根据条件实例化了子类CASUpdater或者LockedUpdater,然后通过子类来完成具体的工作。CASUpdater和LockedUpdater值的读取和更新最后都是使用sun.misc.Unsafe类的相关操作。CASUpdater使用下面的方法:public native Object getLongVolatile(Object o, long offset); public native void putLongVolatile(Object o, long offset, long x);LockedUpdater使用下面的方法:public native long getLong(Object o, long offset); public native void putLong(Object o, long offset, long x);为了防止操作过程中的指令重排,LockedUpdater使用synchronized进行同步。本文基于JDK1.7.0_67java version "1.7.0_67"_Java™ SE Runtime Environment (build 1.7.0_67-b01)Java HotSpot™ 64-Bit Server VM (build 24.65-b04, mixed mode)内部类AtomicLongFieldUpdater本身是抽象类,通过两个私有的静态内部子类来完成具体的工作。CASUpdater:顾名思义,使用CAS操作对象的成员变量。LockedUpdater:顾名思义,在更新和读取对象的成员变量时,使用对象锁来保证同步。成员变量AtomicLongFieldUpdater是个抽象类,具体的业务逻辑都是交给它的子类实现的,它本身没有包含任何成员变量。函数列表AtomicLongFieldUpdater采用模板方法,它本身定义了一些操作过程,而其中使用的具体的方法则由各个子类实现。// 受保护的无操作构造函数,供子类使用 protected AtomicLongFieldUpdater() // 为对象创建并返回一个具有给定字段的更新器。 public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) // 以原子方式设置当前值为update。 // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // CASUpdater的实现该不阻塞 // LockedUpdater的实现通过synchronized进行同步,会阻塞 public abstract boolean compareAndSet(T obj, long expect, long update) // 以原子方式设置当前值为update。 // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // CASUpdater的实现该不阻塞 // LockedUpdater的实现通过synchronized进行同步,会阻塞 // 该过程不保证volatile成员的happens-before语义顺序 public abstract boolean weakCompareAndSet(T obj, long expect, long update) // 以原子方式设置当前值为newValue // CASUpdater的实现使用Unsafe类的putLongVolatile进行操作,具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 public abstract void set(T obj, long newValue) // 以原子方式设置当前值为newValue // CASUpdater的实现使用Unsafe类的putOrderedLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 优先保证对值的修改,而不保证可见性 public abstract void lazySet(T obj, long newValue) // 以原子方式获取当前值 // CASUpdater的实现使用Unsafe类的getLongVolatile进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的getLong进行操作,具有原子性 public abstract long get(T obj) // 以原子方式设置当前值为newValue,并返回更新前的值 // CASUpdater的实现使用Unsafe类的compareAndSwapLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 操作过程中使用自旋方式,直到操作成功 public long getAndSet(T obj, long newValue) // 以原子方式将当前值加1,并返回更新前的值 // CASUpdater的实现使用Unsafe类的compareAndSwapLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 操作过程中使用自旋方式,直到操作成功 public long getAndIncrement(T obj) // 以原子方式将当前值减1,并返回更新前的值 // CASUpdater的实现使用Unsafe类的compareAndSwapLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 操作过程中使用自旋方式,直到操作成功 public long getAndDecrement(T obj) // 以原子方式将当前值加上给定值delta,并返回更新前的值 // CASUpdater的实现使用Unsafe类的compareAndSwapLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 操作过程中使用自旋方式,直到操作成功 public long getAndAdd(T obj, long delta) // 以原子方式将当前值加1,并返回更新后的值 // CASUpdater的实现使用Unsafe类的compareAndSwapLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 操作过程中使用自旋方式,直到操作成功 public long incrementAndGet(T obj) // 以原子方式将当前值减1,并返回更新前的值 // CASUpdater的实现使用Unsafe类的compareAndSwapLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 操作过程中使用自旋方式,直到操作成功 public long decrementAndGet(T obj) // 以原子方式将当前值加上给定值delta,并返回更新后的值 // CASUpdater的实现使用Unsafe类的compareAndSwapLong进行操作,所以本身具有原子性 // LockedUpdater的实现使用synchronizde和Unsafe类的putLong进行操作,具有原子性 // 操作过程中使用自旋方式,直到操作成功 public long addAndGet(T obj, long delta)重点函数分析newUpdater为对象创建并返回一个具有给定字段的更新器实例。由于要操作long型数据,因此要根据虚拟机是否支持原子化更新long来创建对于的子类。当虚拟机支持原子化更新long时,创建CASUpdater实例。否则,创LockedUpdater实例,32位虚拟机不支持对long的原子化更新,因此,只能使用对象锁来保证原子操作。public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { Class<?> caller = Reflection.getCallerClass(); if (AtomicLong.VM_SUPPORTS_LONG_CAS) return new CASUpdater<U>(tclass, fieldName, caller); else return new LockedUpdater<U>(tclass, fieldName, caller); }AtomicLongFieldUpdater受保护的无操作构造函数,供子类实现。无论是CASUpdater还是LockedUpdater,都包含了下面四个成员变量,它们构造函数的实现也是一样的,我们只分析其中CASUpdater的实现。在构造函数中,首先获取要更新的类的指定成员变量fieldName的访问策略(Modifier: public, private, default, protected),然后检查调用类(caller)是否有权限访问该成员变量fieldName,如果没有权限则抛出异常。接下来,判断指定的成员变量fieldName的类型是否是long,如果不是,也抛出异常。接下来,判断当前指定的成员变量是否是volatile类型的,如果不是,也抛出异常。接下来,实例化调用者类cclass,和操作目标类tclass。最后,计算指定成员变量fieldName的内存偏移值。// 成员变量unsafe是原子变量相关操作的基础 // 原子变量的修改操作最终有sun.misc.Unsafe类的CAS操作实现 private static final Unsafe unsafe = Unsafe.getUnsafe(); // 成员变量fieldName的内存偏移值,在构造函数中初始化 private final long offset; // 操作目标类,对该类中的fieldName字段进行更新 private final Class<T> tclass; // 调用者类,通过反射获取 private final Class cclass; CASUpdater(Class<T> tclass, String fieldName, Class<?> caller) { Field field = null; int modifiers = 0; try { // 获取要更新的类的指定成员变量fieldName的访问策略 field = tclass.getDeclaredField(fieldName); modifiers = field.getModifiers(); // 验证访问策略 sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); } catch (Exception ex) { throw new RuntimeException(ex); } // 当前成员变量的类型必须是long Class fieldt = field.getType(); if (fieldt != long.class) throw new IllegalArgumentException("Must be long type"); // 当前成员变量必须是volatile修饰 if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); // 设置调用者类 this.cclass = (Modifier.isProtected(modifiers) && caller != tclass) ? caller : null; // 设置操作目标类 this.tclass = tclass; // 设置成员变量的内存偏移值 offset = unsafe.objectFieldOffset(field); }weakCompareAndSet以原子方式设置当前值为update。如果当前值等于expect,并设置成功,返回true。如果当前值不等于expect,则设置失败,返回false。weakCompareAndSet是通过调用compareAndSet实现的,但是,在JDK文档中声明,weakCompareAndSet不保证volatile的happens-before内存顺序性语义,这是它们的区别。在AtomicLongFieldUpdater类中,这是一个抽象方法。CASUpdater和LockedUpdater有各自的实现。public abstract boolean weakCompareAndSet(T obj, long expect, long update);compareAndSet以原子方式设置当前值为update。如果当前值等于expect,并设置成功,返回true。如果当前值不等于expect,则设置失败,返回false。在AtomicLongFieldUpdater类中,这是一个抽象方法。CASUpdater和LockedUpdater有各自的实现。public abstract boolean compareAndSet(T obj, long expect, long update);CASUpdater的实现当JVM支持long的原子更新时,CASUpdater选择用Unsafe类的compareAndSwapLong方法来直接原子地比较期望值并更新当前值。public boolean compareAndSet(T obj, long expect, long update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapLong(obj, offset, expect, update); } // 类型检查&访问检查 private void fullCheck(T obj) { if (!tclass.isInstance(obj)) throw new ClassCastException(); if (cclass != null) ensureProtectedAccess(obj); } // 访问检查 private void ensureProtectedAccess(T obj) { if (cclass.isInstance(obj)) { return; } throw new RuntimeException( new IllegalAccessException("Class " + cclass.getName() + " can not access a protected member of class " + tclass.getName() + " using an instance of " + obj.getClass().getName() ) ); }LockedUpdater的实现当JVM不支持long的原子更新时,LockedUpdater选择用synchronized对象锁来同步更新操作,其中涉及到当前值是否等于预期值expect,如果相等,则更新,并返回true,否则,不更新,返回false。public boolean compareAndSet(T obj, long expect, long update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { long v = unsafe.getLong(obj, offset); if (v != expect) return false; unsafe.putLong(obj, offset, update); return true; } }get以原子方式获取当前值。在AtomicLongFieldUpdater类中,这是一个抽象方法。CASUpdater和LockedUpdater有各自的实现。public long get(T obj);CASUpdater的实现当JVM支持long的原子更新时,CASUpdater选择用Unsafe类的getLongVolatile方法来直接原子地获取当前值。public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getLongVolatile(obj, offset); }LockedUpdater的实现当JVM不支持long的原子更新时,LockedUpdater选择用synchronized对象锁来同步更新操作。public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { return unsafe.getLong(obj, offset); } }set以原子方式设置当前值为newValue。在AtomicLongFieldUpdater类中,这是一个抽象方法。CASUpdater和LockedUpdater有各自的实现。public abstract void set(T obj, long newValue);CASUpdater的实现当JVM支持long的原子更新时,CASUpdater选择用Unsafe类的putLongVolatile方法来直接原子地更新当前值。public void set(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putLongVolatile(obj, offset, newValue); }LockedUpdater的实现当JVM不支持long的原子更新时,LockedUpdater选择用synchronized对象锁来同步更新操作。public void set(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { unsafe.putLong(obj, offset, newValue); } }lazySet以原子方式设置当前值为newValue。与set方法不同之处在于,lazySet优先保证更新数据,而不保证可见性。因此,更新效率高于set。但是,这种保证只是JDK的设计声明,在子类的实现中,要具体情况具体分析。比如LockedUpdater的lazySet就是调用set方法实现的,本质上一样。在AtomicLongFieldUpdater类中,这是一个抽象方法。CASUpdater和LockedUpdater有各自的实现。public abstract void lazySet(T obj, long newValue);CASUpdater的实现当JVM支持long的原子更新时,CASUpdater选择用Unsafe类的putOrderedLong方法来直接原子地更新当前值。并且,该方法优先保证更新数据,而不保证可见性。效率比putLong高3倍。public void lazySet(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putOrderedLong(obj, offset, newValue); }LockedUpdater的实现当JVM不支持long的原子更新时,LockedUpdater选择调用set方法进行更新,set方法则使用synchronized对象锁来同步更新操作。在LockedUpdater中set方法和lazySet方法没有区别。public void lazySet(T obj, long newValue) { set(obj, newValue); }getAndSet以原子方式设置当前值为newValue,并返回更新前的值。这是一个模板方法,通过在自旋循环中反复调用compareAndSet方法进行操作,而compareAndSet则在不同的子类中有不同的实现。public long getAndSet(T obj, long newValue) { for (;;) { long current = get(obj); if (compareAndSet(obj, current, newValue)) return current; } }类似的方法还有:public long getAndIncrement(T obj) public long getAndDecrement(T obj) public long getAndAdd(T obj, long delta) public long incrementAndGet(T obj) public long decrementAndGet(T obj) public long addAndGet(T obj, long delta) 源码分析之AtomicLongArray https://www.nituchao.com/juc-atomic/22.html 2017-04-11T16:11:00+08:00 概述在原子变量相关类中,AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray三个类是对数组类型的原子类操作,其原理和用法类似,本文重点研究AtomicLongArray。Java原子变量的实现依赖于sun.misc.Unsafe的CAS操作和volatile的内存可见性语义。本文基于JDK1.7.0_67java version "1.7.0_67"__Java(TM) SE Runtime Environment (build 1.7.0_67-b01)Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)成员变量// 成员变量unsafe是原子变量相关操作的基础 // 原子变量的修改操作最终有sun.misc.Unsafe类的CAS操作实现 private static final Unsafe unsafe = Unsafe.getUnsafe(); // arrayBaseOffset获取数组首个元素地址偏移 private static final int base = unsafe.arrayBaseOffset(long[].class); // shift就是数组元素的偏移量 private static final int shift; // 保存数据的数组,在构造函数中初始化 private final long[] array; static { // scale数组元素的增量偏移 int scale = unsafe.arrayIndexScale(long[].class); // 用二进制&操作判断是否是2的倍数,很精彩 // 对于int型数组,scale是4 // 对于lang型数组,scale是8 // 对于Reference型数组,scale是4 if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); // 这里是处理long型的偏移量 // 对于int型的偏移量,shift是2 // 对于lang型的偏移量,shift是3 // 对于Reference型的偏移量,shift是2 shift = 31 - Integer.numberOfLeadingZeros(scale); }函数列表// 构造函数,初始化一个长度为length的空数组 public AtomicLongArray(int length) // 构造函数,通过拷贝给定数组的值进行初始化 // 通过构造函数中final域的内存语义,保证数据可见性 public AtomicLongArray(long[] array) // 检查索引值是否越界,并计算数组中元素的地址 private long checkedByteOffset(int i) // 计算数组中元素的地址,首地址偏移+每个元素的偏移 // 采用了移位操作 private static long byteOffset(int i) // 返回数组长度 public final int length() // 以原子方式获取数组元素 public final long get(int i) // 以原子方式获取数组元素,私有函数 private long getRaw(long offset) // 以原子方式设置数组指定位置为新的值newValue public final void set(int i, long newValue) // 以原子方式设置数组指定位置为新的值newValue // 该函数优先保证对数据的更新,而不保证数据可见性 // 该函数的性能比set函数好很多 public final void lazySet(int i, long newValue) // 以原子方式设置数组指定位置为新的值newValue // 该过程会以自旋的形式循环执行,直到操作成功 // 该过程不会阻塞 // 返回更新前的值 public final long getAndSet(int i, long newValue) // 以原子方式设置数组指定位置为新的值update // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // 该过程不阻塞 public final boolean compareAndSet(int i, long expect, long update) // 以原子方式设置数组指定位置为新的值update // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // 该过程不阻塞 // 私有函数 private boolean compareAndSetRaw(long offset, long expect, long update) // 以原子方式设置数组指定位置为新的值update // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // 该过程不阻塞 // 该过程不保证volatile成员的happens-before语义顺序 public final boolean weakCompareAndSet(int i, long expect, long update) // 以原子方式设置数组指定位置为当前值加1 // 该过程不阻塞 // 返回更新前的值 public final long getAndIncrement(int i) // 以原子方式设置数组指定位置为当前值减1 // 该过程不阻塞 // 返回更新前的值 public final long getAndDecrement(int i) // 以原子方式设置数组指定位置为当前值+delta // 该过程不阻塞 // 返回更新前的值 public final long getAndAdd(int i, long delta) // 以原子方式设置数组指定位置为当前值加1 // 该过程不阻塞 // 返回更新前的值 public final long incrementAndGet(int i) // 以原子方式设置数组指定位置为当前值减1 // 该过程不阻塞 // 返回更新前的值 public final long decrementAndGet(int i) // 以原子方式设置数组指定位置为当前值+delta // 该过程不阻塞 // 返回更新后的值 public long addAndGet(int i, long delta) // 遍历数组中的每一个值,构造字符串 // 返回构造的字符串 public String toString()重要函数分析checkedByOffset(int i)首先判断索引值i是否越界,如果越界,则抛出越界异常。否则,调用byteOffset(int i)函数计算该索引值i对应在数组中的内存偏移值,该偏移值被sun.misc.Unsafe类的函数使用。private long checkedByteOffset(int i) { if (i < 0 || i >= array.length) throw new IndexOutOfBoundsException("index " + i); return byteOffset(i); }byteOffset(int i)根据索引值i,计算数组中元素的地址,首地址偏移+每个元素的偏移private static long byteOffset(int i) { return ((long) i << shift) + base; }lazySet(int i, long newValue)简单点说,lazySet优先保证数据的修改操作,而降低对可见性的要求。lazySet是使用Unsafe.putOrderedLong方法,这个方法在对低延迟代码是很有用的,它能够实现非堵塞的写入,这些写入不会被Java的JIT重新排序指令(instruction reordering),这样它使用快速的存储-存储(store-store) barrier, 而不是较慢的存储-加载(store-load) barrier, 后者总是用在volatile的写操作上,这种性能提升是有代价的,虽然便宜,也就是写后结果并不会被其他线程看到,甚至是自己的线程,通常是几纳秒后被其他线程看到,这个时间比较短,所以代价可以忍受。类似Unsafe.putOrderedLong还有unsafe.putOrderedObject等方法,unsafe.putOrderedLong比使用 volatile long要快3倍左右。public final void lazySet(int i, long newValue) { unsafe.putOrderedLong(array, checkedByteOffset(i), newValue); }getAndSet(int i, long newValue)以原子方式设置数组指定位置为新的值newValue,该过程会以自旋的形式循环执行,直到操作成功。该过程不会阻塞。因为该函数包含两个操作(get和set),因此需要使用自旋方式通过sun.misc.Unsafe的CAS操作保证原子性。public final long getAndSet(int i, long newValue) { long offset = checkedByteOffset(i); while (true) { long current = getRaw(offset); if (compareAndSetRaw(offset, current, newValue)) return current; } }toString()通过遍历数组中元素来构造字符串,并返回。该函数是线程不安全的,在操作过程中内容可能会发生变化,使得AtomicLongArray具有若一致性。public String toString() { int iMax = array.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) { b.append(getRaw(byteOffset(i))); if (i == iMax) return b.append(']').toString(); b.append(',').append(' '); } } 源码分析之AtomicIntegerFieldUpdater https://www.nituchao.com/juc-atomic/20.html 2017-04-02T16:09:00+08:00 概述在原子变量相关类中,AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater三个类是用于原子地修改对象的成员属性,它们的原理和用法类似,区别在于对Integer,Long,Reference类型的成员属性进行修改。本文重点研究AtomicIntegerFieldUpdater。AtomicIntegerFieldUpdater的设计非常有意思。AtomicIntegerFieldUpdater本身是一个抽象类,只有一个受保护的构造函数,它本身不能被实例化。在AtomicIntegerFieldUpdater中定义了一些基本的模板方法,然后通过一个静态内部子类AtomicIntegerFieldUpdaterImpl来实现具体的操作。AtomicIntegerFieldUpdaterImpl中的相关操作也都是基于Unsafe类来实现的。本文基于JDK1.7.0_67java version "1.7.0_67"_Java™ SE Runtime Environment (build 1.7.0_67-b01)Java HotSpot™ 64-Bit Server VM (build 24.65-b04, mixed mode)内部类AtomicIntegerFieldUpdater本身是一个抽象类,通过一个静态内部子类来实现相关的操作。private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T>成员变量AtomicIntegerFieldUpdater是个抽象类,具体的业务逻辑都是交给它的子类实现的,它本身没有包含任何成员变量。函数列表// 受保护的无操作构造函数,供子类使用 protected AtomicIntegerFieldUpdater() // 为对象创建并返回一个具有给定字段的更新器。 public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) // 以原子方式设置当前值为update // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // 该过程通过CAS实现,不阻塞 public abstract boolean compareAndSet(T obj, int expect, int update) // 以原子方式设置当前值为update // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // 该过程通过CAS实现,不阻塞 // 该过程不保证volatile成员的happens-before语义顺序 public abstract boolean weakCompareAndSet(T obj, int expect, int update) // 以原子方式设置当前值为newValue // 使用Unsafe类的putIntVolatile进行操作,具有原子性 public abstract void set(T obj, int newValue) // 以原子方式设置当前值为newValue // 使用Unsafe类的putOrderedInt进行操作,所以本身具有原子性 public abstract void lazySet(T obj, int newValue) // 以原子方式获取当前值 // 使用Unsafe类的getIntVolatile进行操作,所以本身具有原子性 public abstract int get(T obj) // 以原子方式设置当前值为newValue,并返回更新前的值 // 使用Unsafe类的compareAndSwapInt进行操作,所以本身具有原子性 // 操作过程中使用自旋方式,直到操作成功 public int getAndSet(T obj, int newValue) // 以原子方式将当前值加1,并返回更新前的值 // 使用Unsafe类的compareAndSwapInt进行操作,所以本身具有原子性 // 操作过程中使用自旋方式,直到操作成功 public int getAndIncrement(T obj) // 以原子方式将当前值减1,并返回更新前的值 // 使用Unsafe类的compareAndSwapInt进行操作,所以本身具有原子性 // 操作过程中使用自旋方式,直到操作成功 public int getAndDecrement(T obj) // 以原子方式将当前值加上给定值delta,并返回更新前的值 // 使用Unsafe类的compareAndSwapInt进行操作,所以本身具有原子性 // 操作过程中使用自旋方式,直到操作成功 public int getAndAdd(T obj, int delta) // 以原子方式将当前值加1,并返回更新后的值 // 使用Unsafe类的compareAndSwapInt进行操作,所以本身具有原子性 // 操作过程中使用自旋方式,直到操作成功 public int incrementAndGet(T obj) // 以原子方式将当前值减1,并返回更新前的值 // 使用Unsafe类的compareAndSwapInt进行操作,所以本身具有原子性 // 操作过程中使用自旋方式,直到操作成功 public int decrementAndGet(T obj) // 以原子方式将当前值加上给定值delta,并返回更新后的值 // 使用Unsafe类的compareAndSwapInt进行操作,所以本身具有原子性 // 操作过程中使用自旋方式,直到操作成功 public int addAndGet(T obj, int delta)重点函数分析newUpdater为对象创建并返回一个具有给定字段的更新器实例。在该方法中,直接构造一个AtomicIntegerFieldUpdaterImpl实例。public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass()); }AtomicIntegerFieldUpdater受保护的无操作构造函数,供子类实现。AtomicIntegerFieldUpdaterImpl是唯一的子类,我们来看一下他是怎么实现的。在构造函数中,首先获取要更新的类(tclass)的指定成员变量fieldName的访问策略(Modifier: public, private, default, protected),然后检查调用类(caller)是否有权限访问该成员变量fieldName,如果没有权限则抛出异常。接下来,判断指定的成员变量fieldName的类型是否是long,如果不是,也抛出异常。接下来,判断当前指定的成员变量是否是volatile类型的,如果不是,也抛出异常。接下来,实例化调用者类cclass,和操作目标类tclass。最后,计算指定成员变量fieldName的内存偏移值。// 成员变量unsafe是原子变量相关操作的基础 // 原子变量的修改操作最终有sun.misc.Unsafe类的CAS操作实现 private static final Unsafe unsafe = Unsafe.getUnsafe(); // 成员变量fieldName的内存偏移值,在构造函数中初始化 private final long offset; // 操作目标类,对该类中的fieldName字段进行更新 private final Class<T> tclass; // 调用者类,通过反射获取 private final Class cclass; AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName, Class<?> caller) { Field field = null; int modifiers = 0; try { // 获取要更新的类的指定成员变量fieldName的访问策略 field = tclass.getDeclaredField(fieldName); modifiers = field.getModifiers(); // 验证访问策略 sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); } catch (Exception ex) { throw new RuntimeException(ex); } // 当前成员变量的类型必须是int Class fieldt = field.getType(); if (fieldt != int.class) throw new IllegalArgumentException("Must be integer type"); // 当前成员变量必须是volatile修饰 if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); // 设置调用者类 this.cclass = (Modifier.isProtected(modifiers) && caller != tclass) ? caller : null; // 设置目标操作类 this.tclass = tclass; // 设置成员变量的内存偏移值 offset = unsafe.objectFieldOffset(field); }weakCompareAndSet以原子方式设置当前值为update。如果当前值等于expect,并设置成功,返回true。如果当前值不等于expect,则设置失败,返回false。weakCompareAndSet的实现与compareAndSet完全相同,但是,在JDK文档中声明,weakCompareAndSet不保证volatile的happens-before内存顺序性语义,这是它们的区别。在AtomicIntegerFieldUpdater类中,这是一个抽象方法。具体的实现在子类AtomicIntegerFieldUpdaterImpl提供。public abstract boolean weakCompareAndSet(T obj, int expect, int update);AtomicIntegerFieldUpdaterImpl中weakCompareAndSet方法的实现如下:public boolean weakCompareAndSet(T obj, int expect, int update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapInt(obj, offset, expect, update); }compareAndSet以原子方式设置当前值为update。如果当前值等于expect,并设置成功,返回true。如果当前值不等于expect,则设置失败,返回false。在AtomicIntegerFieldUpdater类中,这是一个抽象方法。具体的实现在子类AtomicIntegerFieldUpdaterImpl提供。public abstract boolean compareAndSet(T obj, int expect, int update);AtomicIntegerFieldUpdaterImpl中的compareAndSet方法的实现如下:public boolean compareAndSet(T obj, int expect, int update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapInt(obj, offset, expect, update); } private void fullCheck(T obj) { if (!tclass.isInstance(obj)) throw new ClassCastException(); if (cclass != null) ensureProtectedAccess(obj); } private void ensureProtectedAccess(T obj) { if (cclass.isInstance(obj)) { return; } throw new RuntimeException( new IllegalAccessException("Class " + cclass.getName() + " can not access a protected member of class " + tclass.getName() + " using an instance of " + obj.getClass().getName() ) ); }get以原子方式获取当前值。通过Unsafe的getIntVolatile保证原则性。在AtomicIntegerFieldUpdater类中,这是一个抽象方法。具体的实现在子类AtomicIntegerFieldUpdaterImpl提供。public abstract int get(T obj);AtomicIntegerFieldUpdaterImpl中的get方法的实现如下:public final int get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getIntVolatile(obj, offset); }set以原子方式设置当前值为newValue。通过Unsafe的putIntVolatile保证原子性。在AtomicIntegerFieldUpdater类中,这是一个抽象方法。具体的实现在子类AtomicIntegerFieldUpdaterImpl提供。public abstract void set(T obj, int newValue);AtomicIntegerFieldUpdaterImpl中的set方法的实现如下。public void set(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putIntVolatile(obj, offset, newValue); }lazySet以原子方式设置当前值为newValue。与set方法的区别在于使用Unsafe类的putOreredInt保证原子性,同时该方法优先保证数据的更新,而不保证可见性,效率高。在AtomicIntegerFieldUpdater类中,这是一个抽象方法。具体的实现在子类AtomicIntegerFieldUpdaterImpl提供。public abstract void lazySet(T obj, int newValue);AtomicIntegerFieldUpdaterImpl中的lazySet方法的实现如下:public void lazySet(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putOrderedInt(obj, offset, newValue); }getAndSet以原子方式将当前值更新为newValue,并返回更新前的值。在AtomicIntegerFieldUpdater类中,这是一个模板方法。该方法通过自旋的方式循环调用compareAndSet方法,直到操作成功。public int getAndSet(T obj, int newValue) { for (;;) { int current = get(obj); if (compareAndSet(obj, current, newValue)) return current; } }类似的方法还有如下几个,它们的实现大同小异,不在一一列举:public int getAndSet(T obj, int newValue) public int getAndIncrement(T obj) public int getAndDecrement(T obj) public int getAndAdd(T obj, int delta) public int incrementAndGet(T obj) public int decrementAndGet(T obj) public int addAndGet(T obj, int delta) 源码分析之AtomicLong https://www.nituchao.com/juc-atomic/21.html 2017-03-07T16:10:00+08:00 概述在原子变量相关类中,AtomicBoolean, AtomicInteger, AtomicLong三个类是对于基本数据类型的操作,其原理和用法类似,区别在于Boolean, Integer, Long分别是8位,32位,64位的类型,本文重点研究AtomicLong。Boolean类型数据长度为8位,Integer类型数据是32位,在当前32位操作系统或者64位操作中都能够直接对其进行原子修改和读取。而Long类型数据是64位,在32位JVM上会当做两个分离的32位来进行操作,所以本身不具备原子性。还好我们现在的JDK基本都已经更新到64位,对long型数据的直接修改不存在原子性问题,但是当出现运算操作(比如++, —等)时还是会出现性问题,AtomicLong的目的是实现Long类型数据的各种原子操作。Java原子变量的实现依赖于sun.misc.Unsafe的CAS操作和volatile的内存可见性语义。本文基于JDK1.7.0_67java version "1.7.0_67"__Java(TM) SE Runtime Environment (build 1.7.0_67-b01)Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)成员变量// 成员变量unsafe是原子变量相关操作的基础 // 原子变量的修改操作最终有sun.misc.Unsafe类的CAS操作实现 private static final Unsafe unsafe = Unsafe.getUnsafe(); // 成员变量value的内存偏移值,在静态代码块中初始化 private static final long valueOffset; // 通过volatile关键字保证可见性,用于保存值 private volatile long value; // 记录当前虚拟机是否支持long的原子化操作,如果支持,可以使用CAS进行更新 // 这个问题主要是针对32位JVM对long的更新 static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); static { try { valueOffset = unsafe.objectFieldOffset (AtomicLong.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }函数列表// 构造函数,初始化值为0 public AtomicLong() // 构造函数,指定初始化值 public AtomicLong(long initialValue) // 以原子方式获取当前值 public final long get() // 以原子方式设置当前值为newValue // 赋值语句是单操作,所以本身具有原子性 public final void set(long newValue) // 最后设置为给定值。延时设置变量值,这个等价于set()方法, // 但是由于字段是volatile类型的,因此此字段的修改会比普通字段 //(非volatile字段)有稍微的时间延时(尽管可以忽略),所以如果 // 不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很 // 有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修 // 改新值的任务,原线程就不等待修改结果立即返回。 public final void lazySet(long newValue) // 以原子方式设置当前值为newValue,并返回旧值 public final long getAndSet(long newValue) // 以原子方式设置当前值为update。 // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // 该过程不阻塞 public final boolean compareAndSet(long expect, long update) // 以原子方式设置当前值为update。 // 如果当前值等于expect,并设置成功,返回true // 如果当前值不等于expect,则设置失败,返回false // 该过程不阻塞 // 该过程不保证volatile成员的happens-before语义顺序 public final boolean weakCompareAndSet(long expect, long update) // 以原子的方式将当前值加1 // 该过程以自旋锁的形似循环执行,直到操作成功 // 该过程不会阻塞 // 返回更新前的值 public final long getAndIncrement() // 以原子的方式将当前值减1 // 该过程以自旋的形式循环执行,直到操作成功 // 该过程不会阻塞 // 返回更新前的值 public final long getAndDecrement() // 以原子方式将原值加上给定的delta // 该过程以自旋的形式循环执行,直到操作成功 // 该过程不会阻塞 // 返回更新前的值 public final long getAndAdd(long delta) // 以原子方式将原值加1 // 该过程以自旋的形式循环执行,直到操作成功 // 该过程不会阻塞 // 返回更新后的值 public final long incrementAndGet() // 以原子方式将原值减1 // 该过程以自旋的形式循环执行,直到操作成功 // 该过程不会阻塞 // 返回更新后的值 public final long decrementAndGet() // 以原子方式将原值加上给定的delta // 该过程以自旋的形式循环执行,直到操作成功 // 该过程不会阻塞 // 返回更新后的值 public final long addAndGet(long delta) // 将当前值使用Long的静态方法转换成String类型,并返回 public String toString() // 将当前值使用强制类型转换成int类型,并返回 public int intValue() // 直接返回当前值 public long longValue() // 将当前值使用强制类型转换成float类型,并返回 public float floatValue() // 将当前值使用强制类型转换成double类型,并返回 public double doubleValue()重点函数分析setpublic final void set(long newValue) { value = newValue; }以原子方式设置当前值为newValue,因为set方法只是一个单操作的赋值语句,因此是原子的。加上volatile的内存可见性保证,Set是原子操作无疑。lazySetpublic final void lazySet(long newValue) { unsafe.putOrderedLong(this, valueOffset, newValue); }简单点说,lazySet优先保证数据的修改操作,而降低对可见性的要求。lazySet是使用Unsafe.putOrderedObject方法,这个方法在对低延迟代码是很有用的,它能够实现非堵塞的写入,这些写入不会被Java的JIT重新排序指令(instruction reordering),这样它使用快速的存储-存储(store-store) barrier, 而不是较慢的存储-加载(store-load) barrier, 后者总是用在volatile的写操作上,这种性能提升是有代价的,虽然便宜,也就是写后结果并不会被其他线程看到,甚至是自己的线程,通常是几纳秒后被其他线程看到,这个时间比较短,所以代价可以忍受。类似Unsafe.putOrderedObject还有unsafe.putOrderedLong等方法,unsafe.putOrderedLong比使用 volatile long要快3倍左右。compareAndSetpublic final boolean compareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); }以原子方式设置当前值为update。如果当前值等于expect,并设置成功,返回true。如果当前值不等于expect,则设置失败,返回false。该过程不阻塞。由于是使用了sun.misc.Unsafe的CAS操作实现,它是原子操作无疑。_set和compareAndSet都是原子操作,只是他们的目的不同,set只是单纯想设置一个新的值。而compareAndSet则是希望在满足一定条件的情况下(当前值等于except)再设置新的值。weakCompareAndSetpublic final boolean weakCompareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); }以原子方式设置当前值为update。它的实现与compareAndSet完全一致。JDK文档中说,weakCompareAndSet在更新变量时并不创建任何happens-before顺序,因此即使要修改的值是volatile的,也不保证对该变量的读写操作的顺序(一般来讲,volatile的内存语义保证happens-before顺序)。参考:Java并发——原子变量和原子操作AtomicInteger lazySet vs setJava Atomic Variable set() vs compareAndSet()