atomicinteger如何保证原子性(并发编程九继续探索j)
今天继续探索j.u.c中的12个原子操作Atomic,可以进行分为四组。基本类型、数组类型、引用类型、属性类型。这些类都是采用Unsafe中的方法进行实现。
基本类型Atomic提供以下几个类
- AtomicBoolean
- AtomicLong
- AtomicInteger
它们的实现方法都类似,采用Unsafe实现,如AtomicInteger为例
static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }
上面代码是根据类中‘‘value’’字段取内存地址,而value采用 volatile字段进行修饰
private volatile int value;
AtomicInteger主要方法
- get() //获取值
- getAndIncrement() //当前值加1, 并返回 旧值
- getAndDecrement() //当前值减1,并返回 旧值
- incrementAndGet() //当前值加1并返回新值
- decrementAndGet() //当前值减1并返回新值
- compareAndSet(expect,update) //当前值为预期值时, 更新新值
面试题
- 请回答以下代码的值分别是什么 ?
public class AtomicIntegerDemo { public static void main(String[] args) { AtomicInteger atomic = new AtomicInteger(); System.out.println(atomic.getAndIncrement()); System.out.println(atomic.incrementAndGet()); atomic.lazySet(4); System.out.println(atomic.compareAndSet(2,4)); System.out.println(atomic.get()); } }
2.为什么AtomicBoolean源码中value为什么是int类型?
数据类型Atomic提供以下几个类:
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray
采用原子数组方式实现
private static final int shift; private final int[] array; static { int scale = unsafe.arrayIndexScale(int[].class); if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); shift = 31 - Integer.numberOfLeadingZeros(scale); }
AtomicIntegerArrary主要的方法:
- addAndGet //对指定下标的值进行两值相加并返回
- compareAndSet //对指定下标的值,若为期待值时进行赋值返回 true
- get //返回指定下标的值
- getAndIncrement
- incrementAndGet
- getAndDecrement
- decrementAndGet
AtomicReferenceArray构造方法必须有参数,初始化组数长度。在每次操作时跟数组操作是一样的,每次操作都要带着下标去操作方法
AtomicReferenceArray<User> array = new AtomicReferenceArray<>(1);
面试题
1.请回答以下代码输出结果是什么?
public class AtomicIntegerArrayDemo { public static void main(String[] args) { int[] v =new int[]{1,2}; AtomicIntegerArray array = new AtomicIntegerArray(v); System.out.println(array.addAndGet(0,3)); System.out.println(array.get(0)); System.out.println(array.compareAndSet(1,2,10)); System.out.println(array.get(1)); } }
引用类型Atomic提供以下几个类
- AtomicReference //原子引用类型
- AtomicMarkableReference //带有标记位的引用类型
- AtomicStampedReference //带有版本号的引用类型
AtomicReference的实现方式与基本类型实现相同,但不同的是V是可变对象,而不像基本类型那样是具体的基本类型。
static { try { valueOffset = unsafe.objectFieldOffset (AtomicReference.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile V value;
AtomicMarkableReference是解决ABA的问题, 它不关心版本号,关心的是数据是否有变化
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, boolean mark) { return new Pair<T>(reference, mark); } } private volatile Pair<V> pair;
AtomicStampedReference的实现与AtomicMarkableReference的实现类似。也是解决ABA问题,
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;
属性类型Atomic提供以下几个类
- AtomicIntegerFieldUpdater //整型字段更新器
- AtomicLongFieldUpdater //长整型字段更新器
- AtomicReferenceFieldUpdater //引用字段的更新器
AtomicIntegerFieldUpdater主要方法
- newUpdater
- incrementAndGet
- getAndIncrement
- getAndDecrement
- get
- getAndAdd
- getAndSet
- decrementAndGet
- lazySet
这些方法的原理跟上面的类都差不多,这里就不加注释了非常好理解。
AtomicIntegerFieldUpdater是个抽象类,不通过直接new对象,而需要使用静态方法创建对象, 请看源码
public abstract class AtomicIntegerFieldUpdater<T> { @CallerSensitive public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { return new AtomicIntegerFieldUpdaterImpl<U> (tclass, fieldName, Reflection.getCallerClass()); }
在newUpdater 方法以下几个要求
- 第一个参数是个类类型
- 第二个参数是 更新的字段名
- 字段名必须是volatile int 进行修饰
示例代码,顺序请回答下结果
public class AtomicIntegerFieldUpdaterDemo { public static void main(String[] args) { AtomicIntegerFieldUpdater<User> updater = AtomicIntegerFieldUpdater.newUpdater(User.class, "name"); System.out.println(updater.get(new User())); System.out.println(updater.incrementAndGet(new User())); System.out.println(updater.getAndIncrement(new User())); } static class User { volatile int name; } }
AtomicReferenceFieldUpdater 的常用方法
- newUpdater //
- get //获取指定对象字段的值
- set //设置指定对象字段的值
- getAndAccumulate //通过指定对象的值与当前值进行计算,返回旧值
- getAndSet //设置指定对象字段的值,返回旧值
- getAndUpdate //1.8 计算 返回 旧值
- lazySet
示例代码,并回答下执行结果
public class AtomicReferenceFieldUpdaterDemo { public static void main(String[] args) { AtomicReferenceFieldUpdater updater = AtomicReferenceFieldUpdater.newUpdater(User.class,String.class ,"name"); User user = new User(); user.name = "hello"; System.out.println(updater.getAndAccumulate(user, "java",new BinaryOperator<String>() { @Override public String apply(String s, String s2) { return s " " s2; } })); System.out.println(updater.getAndUpdate(user,(x)->x " word")); System.out.println(user.name); } static class User{ volatile String name; } }
以上是根据个人理解做了分析,如有不正确请留言讨论。
----------------------------------------------------------
再次感谢,欢迎关注微信公众号“零售云技术”,文章持续更新,或留言讨论
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com