学习笔记 03 --- JUC原子类


学习笔记 03 — JUC原子类


JUC ——- Java.util.concurrent包:




Java 5 之后添加了一个新的包JUC 包到Java平台,JUC包包含许多线程安全、测试良好、高性能的并发构建块。不客气地说,创建JUC 的目的就是要实现 Collection 框架对数据结构所执行的并发操作。通过提供一组可靠的、高性能并发构建块,开发人员可以提高并发类的线程安全、可伸缩性、性能、可读性和可靠性。



JUC包包含concurrent,atomic,locks 三个包:


Concurrent:构建的一些高级的工具,如线程池,并发队列等。

Atomic:原子数据的构建。

Locks:基本的锁的实现,最重要的AQS框架和lockSupport。



CAS操作:


JUC包中的许多类都用到了CAS(compare-and-swap)操作。CAS 是一种低级别的、细粒度的技术,它允许多个线程更新一个内存位置,同时能够检测其他线程的冲突并进行恢复。它是许多高性能并发算法的基础。在 JDK 5.0 之前,Java 语言中用于协调线程之间的访问的惟一原语是同步,同步是更重量级和粗粒度的。公开 CAS 可以开发高度可伸缩的并发 Java 类。这些更改主要由 JDK 库类使用,而不是由开发人员使用。CAS操作都封装在java 不公开的类库中,sun.misc.Unsafe点击查看有关Unsafe的详解)。此类包含了对原子操作的封装,具体用本地代码实现。本地的C代码直接利用到了硬件上的原子操作。

关于CAS:一种无锁机制,比较并交换, 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可”。

CAS这样怎么实现线程安全呢?其实我们在语言层面是没有做任何同步的操作的,大家也可以看到源码没有任何锁加在上面,可它为什么是线程安全的呢?这就是Atomic包下这些类的奥秘:语言层面不做处理,我们将其交给硬件—CPU和内存,利用CPU的多处理能力,实现硬件层面的阻塞,再加上volatile变量的特性即可实现基于原子操作的线程安全。所以说,CAS并不是无阻塞,只是阻塞并非在语言、线程方面,而是在硬件层面,所以无疑这样的操作会更快更高效!



CAS的优缺点

优点:操作系统级别的支持,效率更高,无锁机制,降低线程的等待,实际上是把这个任务丢给了操作系统来做。 

缺点:CAS虽然很高效的实现了原子操作,但是它依然存在三个问题。

1、ABA问题。CAS在操作值的时候检查值是否已经变化,没有变化的情况下才会进行更新。但是如果一个值原来是A,变成B,又变成A,那么CAS进行检查时会认为这个值没有变化,但是实际上却变化了。ABA问题的解决方法是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就变成1A-2B-3A。从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。

2、并发越高,失败的次数会越多,CAS如果长时间不成功,会极大的增加CPU的开销。因此CAS不适合竞争十分频繁的场景。

3、只能保证一个共享变量的原子操作。当对多个共享变量操作时,CAS就无法保证操作的原子性,这时就可以用锁,或者把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象的原子性,你可以把多个变量放在一个对象里来进行CAS操作。




JUC之原子类Atomic


原子类这个包里面提供了一组原子变量类,其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的,不会阻塞线程(或者说只是在硬件级别上阻塞了)。可以对基本数据、数组中的基本数据、对类中的基本数据进行操作。原子变量类相当于一种泛化的volatile变量,能够支持原子的和有条件的读-改-写操作。


注意:有关原子量的用法很简单,关键是对原子量的认识,原子仅仅是保证变量操作的原子性,但整个程序还需要考虑线程安全的。


JUC包中的原子类如图所示:


《学习笔记 03 --- JUC原子类》


根据修改的数据类型,JUC包中的原子类可以分成4类:


1.基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;

AtomicInteger, AtomicLong, AtomicBoolean这三个基本类型的原子类的原理和用法相似,所以就不一一总结了,只针对AtomicLong这个类来进行总结。AtomicLong的源码如下:

/* * @(#)AtomicLong.java 1.12 06/06/15 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util.concurrent.atomic; import sun.misc.Unsafe; /** * A {@code long} value that may be updated atomically. See the * {@link java.util.concurrent.atomic} package specification for * description of the properties of atomic variables. An * {@code AtomicLong} is used in applications such as atomically * incremented sequence numbers, and cannot be used as a replacement * for a {@link java.lang.Long}. However, this class does extend * {@code Number} to allow uniform access by tools and utilities that * deal with numerically-based classes. * * @since 1.5 * @author Doug Lea */ public class AtomicLong extends Number implements java.io.Serializable { private static final long serialVersionUID = 1927816293512124184L; // setup to use Unsafe.compareAndSwapLong for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; /** * Records whether the underlying JVM supports lockless * CompareAndSet for longs. While the unsafe.CompareAndSetLong * method works in either case, some constructions should be * handled at Java level to avoid locking user-visible locks. */ static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); /** * Returns whether underlying JVM supports lockless CompareAndSet * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS. */ private static native boolean VMSupportsCS8(); static { try { valueOffset = unsafe.objectFieldOffset (AtomicLong.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile long value; /** * Creates a new AtomicLong with the given initial value. * * @param initialValue the initial value */ // 创建值为initialValue的AtomicLong对象 public AtomicLong(long initialValue) { value = initialValue; } /** * Creates a new AtomicLong with initial value {@code 0}. */ // 构造函数 public AtomicLong() { } /** * Gets the current value. * * @return the current value */ // 获取当前值 public final long get() { return value; } /** * Sets to the given value. * * @param newValue the new value */ // 以原子方式设置当前值为newValue public final void set(long newValue) { value = newValue; } /** * Eventually sets to the given value. * * @param newValue the new value * @since 1.6 */ // 最后设置为给定值。延时设置变量值,这个等价于set()方法,但是由于字段是volatile类型的,因此次字段的修改会比普通字段(非volatile字段)有稍微的性能延时(尽管可以忽略), //所以如果不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修改新值的任务, //原线程就不等待修改结果立即返回(这种解释其实是不正确的,但是可以这么理解)。 public final void lazySet(long newValue) { unsafe.putOrderedLong(this, valueOffset, newValue); } /** * Atomically sets to the given value and returns the old value. * * @param newValue the new value * @return the previous value */ // 以原子方式设置当前值为newValue,并返回旧值 public final long getAndSet(long newValue) { while (true) { long current = get(); if (compareAndSet(current, newValue)) return current; } } /** * 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 true if successful. False return indicates that * the actual value was not equal to the expected value. */ // 如果当前值 == expect,则以原子方式将该值设置为update。成功返回true,否则返回false,并且不修改原值 public final boolean compareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); } /** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> * 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 true if successful. */ // 如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。JSR规范中说:以原子方式读取和有条件地写入变量但不 创建任何 happen-before 排序,因此不提供与除 weakCompareAndSet //目标外任何变量以前或后续读取或写入操作有关的任何保证。大意就是说调用weakCompareAndSet时并不能保证不存在happen-before的发生(也就是可能存在指令重排序导致此操作失败)。 //但是从Java源码来看,其实此方法并没有实现JSR规范的要求,最后效果和compareAndSet是等效的,都调用了unsafe.compareAndSwapInt()完成操作。 public final boolean weakCompareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); } /** * Atomically increments by one the current value. * * @return the previous value */ // 以原子方式将当前值加 1,并返回加1前的值。等价于“num++” public final long getAndIncrement() { while (true) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return current; } } /** * Atomically decrements by one the current value. * * @return the previous value */ // 以原子方式将当前值减 1,并返回减1前的值。等价于“num--” public final long getAndDecrement() { while (true) { long current = get(); long next = current - 1; if (compareAndSet(current, next)) return current; } } /** * Atomically adds the given value to the current value. * * @param delta the value to add * @return the previous value */ // 以原子方式将delta添加到当前值,并返回相加前的值。 public final long getAndAdd(long delta) { while (true) { long current = get(); long next = current + delta; if (compareAndSet(current, next)) return current; } } /** * Atomically increments by one the current value. * * @return the updated value */ // 以原子方式将当前值加 1,并返回加1后的值。等价于“++num” public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return next; } } /** * Atomically decrements by one the current value. * * @return the updated value */ // 以原子方式将当前值减 1,并返回减1后的值。等价于“--num” public final long decrementAndGet() { for (;;) { long current = get(); long next = current - 1; if (compareAndSet(current, next)) return next; } } /** * Atomically adds the given value to the current value. * * @param delta the value to add * @return the updated value */ // 以原子方式将delta与当前值相加,并返回相加后的值。 public final long addAndGet(long delta) { for (;;) { long current = get(); long next = current + delta; if (compareAndSet(current, next)) return next; } } /** * Returns the String representation of the current value. * @return the String representation of the current value. */ //返回当前值对应的字符串 public String toString() { return Long.toString(get()); } // 返回当前值对应的int值 public int intValue() { return (int)get(); } // 获取当前值对应的long值 public long longValue() { return (long)get(); } // 以 float 形式返回当前值 public float floatValue() { return (float)get(); } // 以 double 形式返回当前值 public double doubleValue() { return (double)get(); } } 

说明:

AtomicLong是通过“volatile”和“Unsafe提供的CAS函数”实现原子操作。

从源码中我们可以看到value是一个volatile类型的变量,当我们使用源码中的一些方法时,首先会根据get()获取主存中原来的值,然后再对这个值进行加减操作,最后根据CAS函数来比较原始值是否与expect值相等,如果相等,则设置原始值为新值,并返回新值或者原始值。

volatile:用volatile修饰的变量,保证了不同线程对这个变量进行操作时的可见性,不会拷贝副本到工作内存中去,系统总是从主存中读取数据,即线程在每次使用变量的时候,都会读取变量修改后的最新值。但是volatile不能保证对变量的修改是有序的。volatile不能保证原子性,之所以JUC包的原子类可以保证原子性是由CAS (compare and swap) + volatile+native方法联合实现的。


2.数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ;

和上面的基本类型一样,AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这三个数组类型的原子类原理和用法相似,我们只举例介绍其中AtomicLongArray这个原子类,AtomicLongArray这个类的源码如下:

/* * @(#)AtomicLongArray.java 1.13 09/11/17 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util.concurrent.atomic; import sun.misc.Unsafe; import java.util.*; /** * A {@code long} array in which elements may be updated atomically. * See the {@link java.util.concurrent.atomic} package specification * for description of the properties of atomic variables. * @since 1.5 * @author Doug Lea */ public class AtomicLongArray implements java.io.Serializable { private static final long serialVersionUID = -2308431214976778248L; // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final int base = unsafe.arrayBaseOffset(long[].class); private static final int scale = unsafe.arrayIndexScale(long[].class); private final long[] array; private long rawIndex(int i) { if (i < 0 || i >= array.length) throw new IndexOutOfBoundsException("index " + i); return base + (long) i * scale; } /** * Creates a new AtomicLongArray of given length. * * @param length the length of the array */ // 创建给定长度的新 AtomicLongArray。 public AtomicLongArray(int length) { array = new long[length]; // must perform at least one volatile write to conform to JMM if (length > 0) unsafe.putLongVolatile(array, rawIndex(0), 0); } /** * Creates a new AtomicLongArray with the same length as, and * all elements copied from, the given array. * * @param array the array to copy elements from * @throws NullPointerException if array is null */ // 创建与给定数组具有相同长度的新 AtomicLongArray,并从给定数组复制其所有元素。 public AtomicLongArray(long[] array) { if (array == null) throw new NullPointerException(); int length = array.length; this.array = new long[length]; if (length > 0) { int last = length-1; for (int i = 0; i < last; ++i) this.array[i] = array[i]; // Do the last write as volatile unsafe.putLongVolatile(this.array, rawIndex(last), array[last]); } } /** * Returns the length of the array. * * @return the length of the array */ // 返回该数组的长度。 public final int length() { return array.length; } /** * Gets the current value at position {@code i}. * * @param i the index * @return the current value */ // 获取位置 i 的当前值。 public final long get(int i) { return unsafe.getLongVolatile(array, rawIndex(i)); } /** * Sets the element at position {@code i} to the given value. * * @param i the index * @param newValue the new value */ // 将位置 i 的元素设置为给定值。 public final void set(int i, long newValue) { unsafe.putLongVolatile(array, rawIndex(i), newValue); } /** * Eventually sets the element at position {@code i} to the given value. * * @param i the index * @param newValue the new value * @since 1.6 */ // 最终将位置 i 的元素设置为给定值。 public final void lazySet(int i, long newValue) { unsafe.putOrderedLong(array, rawIndex(i), newValue); } /** * Atomically sets the element at position {@code i} to the given value * and returns the old value. * * @param i the index * @param newValue the new value * @return the previous value */ // 以原子方式将位置 i 的元素设置为给定值,并返回旧值。 public final long getAndSet(int i, long newValue) { while (true) { long current = get(i); if (compareAndSet(i, current, newValue)) return current; } } /** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * @param i the index * @param expect the expected value * @param update the new value * @return true if successful. False return indicates that * the actual value was not equal to the expected value. */ // 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 public final boolean compareAndSet(int i, long expect, long update) { return unsafe.compareAndSwapLong(array, rawIndex(i), expect, update); } /** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> * and does not provide ordering guarantees, so is only rarely an * appropriate alternative to {@code compareAndSet}. * * @param i the index * @param expect the expected value * @param update the new value * @return true if successful. */ // 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 public final boolean weakCompareAndSet(int i, long expect, long update) { return compareAndSet(i, expect, update); } /** * Atomically increments by one the element at index {@code i}. * * @param i the index * @return the previous value */ // 以原子方式将索引 i 的元素加 1。 public final long getAndIncrement(int i) { while (true) { long current = get(i); long next = current + 1; if (compareAndSet(i, current, next)) return current; } } /** * Atomically decrements by one the element at index {@code i}. * * @param i the index * @return the previous value */ // 以原子方式将索引 i 的元素减 1。 public final long getAndDecrement(int i) { while (true) { long current = get(i); long next = current - 1; if (compareAndSet(i, current, next)) return current; } } /** * Atomically adds the given value to the element at index {@code i}. * * @param i the index * @param delta the value to add * @return the previous value */ // 以原子方式将给定值与索引 i 的元素相加。 public final long getAndAdd(int i, long delta) { while (true) { long current = get(i); long next = current + delta; if (compareAndSet(i, current, next)) return current; } } /** * Atomically increments by one the element at index {@code i}. * * @param i the index * @return the updated value */ // 以原子方式将索引 i 的元素加1。 public final long incrementAndGet(int i) { while (true) { long current = get(i); long next = current + 1; if (compareAndSet(i, current, next)) return next; } } /** * Atomically decrements by one the element at index {@code i}. * * @param i the index * @return the updated value */ // 以原子方式将索引 i 的元素减1。 public final long decrementAndGet(int i) { while (true) { long current = get(i); long next = current - 1; if (compareAndSet(i, current, next)) return next; } } /** * Atomically adds the given value to the element at index {@code i}. * * @param i the index * @param delta the value to add * @return the updated value */ // 以原子方式将给定值添加到索引 i 的元素。 public long addAndGet(int i, long delta) { while (true) { long current = get(i); long next = current + delta; if (compareAndSet(i, current, next)) return next; } } /** * Returns the String representation of the current values of array. * @return the String representation of the current values of array. */ //将给定数组里面的值转化为字符串 public String toString() { if (array.length > 0) // force volatile read get(0); return Arrays.toString(array); } } 

说明:

AtomicLong是作用是对长整形进行原子操作。而AtomicLongArray的作用则是对”长整形数组”进行原子操作。

当我们使用源码中的一些方法时,首先会根据get(int i)获取索引i处的原始值,然后再对这个值进行加减操作,最后根据CAS函数来比较原始值是否与expect值相等,如果相等,则设置原始值为新值,并返回新值或者原始值。


3.引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkableReference ;

AtomicReference是对“对象”进行原子操作,AtomicReference的源代码如下:

/* * @(#)AtomicReference.java 1.12 06/06/15 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util.concurrent.atomic; import sun.misc.Unsafe; /** * An object reference that may be updated atomically. See the {@link * java.util.concurrent.atomic} package specification for description * of the properties of atomic variables. * @since 1.5 * @author Doug Lea * @param <V> The type of object referred to by this reference */ public class AtomicReference<V> implements java.io.Serializable { private static final long serialVersionUID = -1848883965231344442L; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicReference.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile V value; /** * Creates a new AtomicReference with the given initial value. * * @param initialValue the initial value */ // 使用给定的初始值创建新的 AtomicReference。 public AtomicReference(V initialValue) { value = initialValue; } /** * Creates a new AtomicReference with null initial value. */ // 使用 null 初始值创建新的 AtomicReference。 public AtomicReference() { } /** * Gets the current value. * * @return the current value */ // 获取当前值。 public final V get() { return value; } /** * Sets to the given value. * * @param newValue the new value */ // 设置为给定值。 public final void set(V newValue) { value = newValue; } /** * Eventually sets to the given value. * * @param newValue the new value * @since 1.6 */ // 最终设置为给定值。 public final void lazySet(V newValue) { unsafe.putOrderedObject(this, valueOffset, newValue); } /** * 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 true if successful. False return indicates that * the actual value was not equal to the expected value. */ // 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 public final boolean compareAndSet(V expect, V update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); } /** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> * 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 true if successful. */ // 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 public final boolean weakCompareAndSet(V expect, V update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); } /** * Atomically sets to the given value and returns the old value. * * @param newValue the new value * @return the previous value */ // 以原子方式设置为给定值,并返回旧值。 public final V getAndSet(V newValue) { while (true) { V x = get(); if (compareAndSet(x, newValue)) return x; } } /** * Returns the String representation of the current value. * @return the String representation of the current value. */ // 返回当前值的字符串表示形式。 public String toString() { return String.valueOf(get()); } } 

说明:

AtomicReference是通过“volatile”和“Unsafe提供的CAS函数”实现原子操作。

AtomicReference对象的属性不是必须用volatile修饰。

(01) value是volatile类型。这保证了:当某线程修改value的值时,其他线程看到的value值都是最新的value值,即修改之后的volatile的值。
(02) 通过CAS设置value。这保证了:当某线程池通过CAS函数(如compareAndSet函数)设置value时,它的操作是原子的,即线程在操作value时不会被中断

在文章开头我们也提到过原子类的CAS操作会产生ABA问题,wiki官方解释:https://en.wikipedia.org/wiki/ABA_problem,简单讲就是多线程环境,2次读写中一个线程修改A->B,然后又B->A,另一个线程看到的值未改变,又继续修改成自己的期望值。如果我们不关心中间状态的变化,只关心最终结果,就无所谓ABA问题。ABA代码如下:

import java.util.concurrent.atomic.AtomicReference;  
  
public class ABATest {  
    static  AtomicReference<Integer> atomicReference = new AtomicReference<Integer>(1);  
      
    public static void main(String[] args) throws InterruptedException {  
  
       new Thread(new Runnable() {  
                  
                @Override  
                public void run() {  
                    System.out.println(Thread.currentThread()+ "-" + atomicReference.compareAndSet(1, 2));  
                    System.out.println(Thread.currentThread()+ "-" + atomicReference.compareAndSet(2, 1));  
                }  
            }).start();  
          
        new Thread(new Runnable() {  
              
            @Override  
            public void run() {  
                System.out.println(Thread.currentThread()+ "-" + atomicReference.compareAndSet(1, 2));  
            }  
        }).start();  
          
        Thread.currentThread().sleep(3000);  
        System.out.println(atomicReference.get());  
  
    }  
}  

对于ABA问题,JUC包中的原子类里面AtomicStampedRerence, AtomicMarkableReference可以很好的解决ABA问题。看下AtomicStampedRerence是如何解决ABA问题的:

/** 
通过static 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);  
    }  
}  
  
private volatile Pair<V> pair;  
  
/** 
 * 通过传入的初始化引用和计数器来构造函数一个pair 
 * 
 * @param initialRef 初始化用用 
 * @param initialStamp 初始化计数器或者叫时间戳 
 */  
public AtomicStampedReference(V initialRef, int initialStamp) {  
    pair = Pair.of(initialRef, initialStamp);  
}  

AtomicStampedReference通过一个pair来保存初始化引用和计数器,以后每次原子操作时,都需要比较引用和计数器是否都正确。看下AtomicStampedReference的方法:

public boolean compareAndSet(V   expectedReference,  
                             V   newReference,  
                             int expectedStamp,  
                             int newStamp) {  
    Pair<V> current = pair;  
    //每次操作前不但比较引用值还比较计数器,底层还是unsafe那些方法  
    return  
        expectedReference == current.reference &&  
        expectedStamp == current.stamp &&  
        ((newReference == current.reference &&  
          newStamp == current.stamp) ||  
         casPair(current, Pair.of(newReference, newStamp)));  
}  
private boolean casPair(Pair<V> cmp, Pair<V> val) {  
    return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);  
} 

网上找到的一个例子:转自:http://blog.csdn.net/xiaoxufox/article/details/51312354

import java.util.concurrent.atomic.AtomicStampedReference;  
  
public class AtomicStampedReferenceTest {  
  
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(0, 0);  
  
    public static void main(String[] args) throws InterruptedException {  
          
        final int stamp = atomicStampedReference.getStamp();  
        final Integer reference = atomicStampedReference.getReference();  
  
        Thread t1 = new Thread(new Runnable() {  
  
            @Override  
            public void run() {  
                    System.out.println(Thread.currentThread() + "-" + reference + "-" + stamp + "-"  
                            + atomicStampedReference.compareAndSet(reference, reference + 10, stamp, stamp + 1));  
            }  
        });  
          
        Thread t2 = new Thread(new Runnable() {  
  
            @Override  
            public void run() {  
                    Integer reference = atomicStampedReference.getReference();  
                    System.out.println(Thread.currentThread() + "-" + reference + "-" + stamp + "-"  
                            + atomicStampedReference.compareAndSet(reference, reference + 10, stamp, stamp + 1));  
            }  
        });  
          
        t1.start();  
        t2.start();  
        t1.join();  
        t2.join();  
          
        System.out.println(atomicStampedReference.getReference());  
        System.out.println(atomicStampedReference.getStamp());  
    }  
}  

AtomicMarkableReference跟AtomicStampedReference差不多,AtomicStampedReference是使用pair的int stamp作为计数器使用,AtomicMarkableReference的pair使用的是boolean mark。

AtomicStampedReference可能关心的是修改过几次,AtomicMarkableReference关心的是有没有被修改过,方法都比较简单。


AtomicMarkableReference类描述的一个<Object,Boolean>的对,可以原子的修改Object或者Boolean的值,这种数据结构在一些缓存或者状态描述中比较有用。这种结构在单个或者同时修改Object/Boolean的时候能够有效的提高吞吐量。


AtomicStampedReference类维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。对比AtomicMarkableReference类的<Object,Boolean>,AtomicStampedReference维护的是一种类似<Object,int>的数据结构,其实就是对对象(引用)的一个并发计数。但是与AtomicInteger不同的是,此数据结构可以携带一个对象引用(Object),并且能够对此对象和计数同时进行原子操作。


4.对象的属性修改类型: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater ;

AtomicIntegerFieldUpdater, AtomicLongFieldUpdater和AtomicReferenceFieldUpdater这3个修改类的成员的原子类型的原理和用法相似,我们主要以AtomicLongFieldUpdater为例作为总结,源代码如下:

/* * @(#)AtomicLongFieldUpdater.java 1.14 06/06/15 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util.concurrent.atomic; import sun.misc.Unsafe; import java.lang.reflect.*; /** * A reflection-based utility that enables atomic updates to * designated {@code volatile long} fields of designated classes. * This class is designed for use in atomic data structures in which * several fields of the same node are independently subject to atomic * updates. * * <p>Note that the guarantees of the {@code compareAndSet} * method in this class are weaker than in other atomic classes. * Because this class cannot ensure that all uses of the field * are appropriate for purposes of atomic access, it can * guarantee atomicity only with respect to other invocations of * {@code compareAndSet} and {@code set} on the same updater. * * @since 1.5 * @author Doug Lea * @param <T> The type of the object holding the updatable field */ public abstract class AtomicLongFieldUpdater<T> { /** * Creates and returns an updater for objects with the given field. * The Class argument is needed to check that reflective types and * generic types match. * * @param tclass the class of the objects holding the field * @param fieldName the name of the field to be updated. * @return the updater * @throws IllegalArgumentException if the field is not a * volatile long type. * @throws RuntimeException with a nested reflection-based * exception if the class does not hold field or is the wrong type. */ // 为对象创建并返回一个具有给定字段的更新器。 public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { if (AtomicLong.VM_SUPPORTS_LONG_CAS) return new CASUpdater<U>(tclass, fieldName); else return new LockedUpdater<U>(tclass, fieldName); } /** * Protected do-nothing constructor for use by subclasses. */ // 受保护的无操作构造方法,供子类使用。 protected AtomicLongFieldUpdater() { } /** * Atomically sets the field of the given object managed by this updater * to the given updated value if the current value {@code ==} the * expected value. This method is guaranteed to be atomic with respect to * other calls to {@code compareAndSet} and {@code set}, but not * necessarily with respect to other changes in the field. * * @param obj An object whose field to conditionally set * @param expect the expected value * @param update the new value * @return true if successful. * @throws ClassCastException if {@code obj} is not an instance * of the class possessing the field established in the constructor. */ // 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。 public abstract boolean compareAndSet(T obj, long expect, long update); /** * Atomically sets the field of the given object managed by this updater * to the given updated value if the current value {@code ==} the * expected value. This method is guaranteed to be atomic with respect to * other calls to {@code compareAndSet} and {@code set}, but not * necessarily with respect to other changes in the field. * * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> * and does not provide ordering guarantees, so is only rarely an * appropriate alternative to {@code compareAndSet}. * * @param obj An object whose field to conditionally set * @param expect the expected value * @param update the new value * @return true if successful. * @throws ClassCastException if {@code obj} is not an instance * of the class possessing the field established in the constructor. */ // 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。 public abstract boolean weakCompareAndSet(T obj, long expect, long update); /** * Sets the field of the given object managed by this updater to the * given updated value. This operation is guaranteed to act as a volatile * store with respect to subsequent invocations of {@code compareAndSet}. * * @param obj An object whose field to set * @param newValue the new value */ // 将此更新器管理的给定对象的字段设置为给定更新值。 public abstract void set(T obj, long newValue); /** * Eventually sets the field of the given object managed by this * updater to the given updated value. * * @param obj An object whose field to set * @param newValue the new value * @since 1.6 */ // 最后将此更新器管理的给定对象的字段设置为给定更新值。 public abstract void lazySet(T obj, long newValue); /** * Gets the current value held in the field of the given object managed * by this updater. * * @param obj An object whose field to get * @return the current value */ // 获取此更新器管理的在给定对象的字段中保持的当前值。 public abstract long get(T obj); /** * Atomically sets the field of the given object managed by this updater * to the given value and returns the old value. * * @param obj An object whose field to get and set * @param newValue the new value * @return the previous value */ // 将此更新器管理的给定对象的字段以原子方式设置为给定值,并返回旧值。 public long getAndSet(T obj, long newValue) { for (;;) { long current = get(obj); if (compareAndSet(obj, current, newValue)) return current; } } /** * Atomically increments by one the current value of the field of the * given object managed by this updater. * * @param obj An object whose field to get and set * @return the previous value */ // 以原子方式将此更新器管理的给定对象字段的当前值加 1。 public long getAndIncrement(T obj) { for (;;) { long current = get(obj); long next = current + 1; if (compareAndSet(obj, current, next)) return current; } } /** * Atomically decrements by one the current value of the field of the * given object managed by this updater. * * @param obj An object whose field to get and set * @return the previous value */ // 以原子方式将此更新器管理的给定对象字段当前值减 1。 public long getAndDecrement(T obj) { for (;;) { long current = get(obj); long next = current - 1; if (compareAndSet(obj, current, next)) return current; } } /** * Atomically adds the given value to the current value of the field of * the given object managed by this updater. * * @param obj An object whose field to get and set * @param delta the value to add * @return the previous value */ // 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。 public long getAndAdd(T obj, long delta) { for (;;) { long current = get(obj); long next = current + delta; if (compareAndSet(obj, current, next)) return current; } } /** * Atomically increments by one the current value of the field of the * given object managed by this updater. * * @param obj An object whose field to get and set * @return the updated value */ // 以原子方式将此更新器管理的给定对象字段当前值加 1。 public long incrementAndGet(T obj) { for (;;) { long current = get(obj); long next = current + 1; if (compareAndSet(obj, current, next)) return next; } } /** * Atomically decrements by one the current value of the field of the * given object managed by this updater. * * @param obj An object whose field to get and set * @return the updated value */ // 以原子方式将此更新器管理的给定对象字段当前值减 1。 public long decrementAndGet(T obj) { for (;;) { long current = get(obj); long next = current - 1; if (compareAndSet(obj, current, next)) return next; } } /** * Atomically adds the given value to the current value of the field of * the given object managed by this updater. * * @param obj An object whose field to get and set * @param delta the value to add * @return the updated value */ // 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。 public long addAndGet(T obj, long delta) { for (;;) { long current = get(obj); long next = current + delta; if (compareAndSet(obj, current, next)) return next; } } private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> { private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long offset; private final Class<T> tclass; private final Class cclass; CASUpdater(Class<T> tclass, String fieldName) { Field field = null; Class caller = null; int modifiers = 0; try { field = tclass.getDeclaredField(fieldName); caller = sun.reflect.Reflection.getCallerClass(3); 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); } Class fieldt = field.getType(); if (fieldt != long.class) throw new IllegalArgumentException("Must be long type"); 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); } private void fullCheck(T obj) { if (!tclass.isInstance(obj)) throw new ClassCastException(); if (cclass != null) ensureProtectedAccess(obj); } 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); } public boolean weakCompareAndSet(T obj, long expect, long update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapLong(obj, offset, expect, update); } public void set(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putLongVolatile(obj, offset, newValue); } public void lazySet(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putOrderedLong(obj, offset, newValue); } public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getLongVolatile(obj, offset); } 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() ) ); } } private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long offset; private final Class<T> tclass; private final Class cclass; LockedUpdater(Class<T> tclass, String fieldName) { Field field = null; Class caller = null; int modifiers = 0; try { field = tclass.getDeclaredField(fieldName); caller = sun.reflect.Reflection.getCallerClass(3); 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); } Class fieldt = field.getType(); if (fieldt != long.class) throw new IllegalArgumentException("Must be long type"); 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); } private void fullCheck(T obj) { if (!tclass.isInstance(obj)) throw new ClassCastException(); if (cclass != null) ensureProtectedAccess(obj); } 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; } } public boolean weakCompareAndSet(T obj, long expect, long update) { return compareAndSet(obj, expect, update); } public void set(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized(this) { unsafe.putLong(obj, offset, newValue); } } public void lazySet(T obj, long newValue) { set(obj, newValue); } public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized(this) { return unsafe.getLong(obj, offset); } } 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() ) ); } } } 

说明:

AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater基于反射的实用工具,可以对指定类的指定volatile字段进行原子更新。原子更新字段类都是抽象类,每次使用都时候必须使用静态方法newUpdater创建一个更新器。原子更新类的字段的必须使用public volatile修饰符

(1)字段必须是volatile类型的

(2)字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致。也就是说 调用者能够直接操作对象字段,那么就可以反射进行原子操作。但是对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。

(3)只能是实例变量,不能是类变量,也就是说不能加static关键字。

(4)只能是可修改变量,不能使final变量,因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的,这两个关键字不能同时存在。

(5)对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater 。

public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
        return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
    }
public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
        if (AtomicLong.VM_SUPPORTS_LONG_CAS)
            return new CASUpdater<U>(tclass, fieldName);
        else
            return new LockedUpdater<U>(tclass, fieldName);
    }
public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
        return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
                                                        vclass,
                                                        fieldName);
    }

对于AtomicIntegerFieldUpdater, AtomicReferenceFieldUpdater而言newUpdater()的作用是返回CASUpdater对象;

对于AtomicLongFieldUpdater而言newUpdater()的作用是返回CASUpdater对象,或者LockedUpdater对象;具体返回哪一个类取决于JVM是否支持long类型的CAS函数。CASUpdater和LockedUpdater都是AtomicLongFieldUpdater的子类,它们的实现类似;

tclass:被调用的类class

vclass:volatile变量的引用类型class(只有AtomicReferenceFieldUpdater的时候才需要

fieldName:volatile变量的名称



**********************************************未完待续*********************************************

该文为本人学习的笔记,方便以后自己查阅。参考网上各大帖子,取其精华整合自己的理解而成。如有不对的地方,请多多指正!自勉!共勉!

**************************************************************************************************

    原文作者:JUC
    原文地址: https://blog.csdn.net/tianya3530/article/details/54286307
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞