AtomicInteger类处于java.util.concurrent.atomic包下,与其他原子操作的类一样,底层都是采用CAS机制,调用了Unsafe类的CAS方法实现的。我们先分析一下AtomicInteger类的源码,再来分析CAS机制的种种。 继承了 Number, 这主要是提供方法将数值转化为 byte, double 等方便 Java 开发者使用; 实现了 Serializable, 为了网络传输等的序列化用, 编码时最好手动生成序列化 ID, 让 javac 编译器生成开销大, 而且可能造成意想不到的状况。 Unsafe类是一个JDK内部使用的专属类,我们自己的应用程序无法直接使用Unsafe类。通过观察源码,可以知道获得Unsafe实例的方法是调动其工厂方法getUnsafe(),源码如下: 它会检查调用getUnsafe()函数的类,判断调用这的类加载器是否是系统类加载器(系统类加载器为null),如果不是就直接抛出异常,拒绝工作,这也是为什么我们写的程序没法直接使用这个类的原因。 第一个参数var1为给定的对象,var2为对象内的偏移量(其实就是一个字段到对象头部的偏移量,通过这个偏移量可以快速定位字段),var4表示期望值,var5表示要设置的值。如果指定的字段的值等于var4,那么就会把它设置为var5。 CAS全拼又叫做compareAndSwap,从名字上的意思就知道是比较交换的意思。它包含 3 个参数 CAS(V,E,N),V表示要更新变量的值,E表示预期值,N表示新值。仅当 V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做两个更新,则当前线程则什么都不做。最后,CAS 返回当前V的真实值。 CAS是一种乐观锁,而且是一种非阻塞的轻量级的乐观锁。当一个线程想要获得锁,对方会给一个回应表示这个锁能不能获得。在资源竞争不激烈的情况下性能高,相比synchronized重量锁,synchronized会进行比较复杂的加锁,解锁和唤醒操作。 (1) ABA问题 * 问题描述:CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。 * 解决办法: a. 用CAS的一个变种DCAS,DCAS是对于每一个V增加一个引用的表示修改次数的标记符。对于每个V,如果引用修改了一次,这个计数器就加1,然后再这个变量需要更新的时候,就同时检查变量的值和计数器的值。都符合条件才可以修改V值。 b. 通过将标记与要进行CAS操作的每个值相关联,并原子地更新值和标记。也就是一旦V第一次被使用,就不会再重复使用,如有需要则分配新的V。垃圾收集器可以检查V,保证其不被循环使用,直到当前的访问操作全部结束。使用 AtomicStampedReference 来解决CAS中的ABA问题,它不再像compareAndSet方法 中只比较内存中的值也当前值是否相等,而且先比较引用是否相等,然后比较值是否相等。 c. 设置一个版本号,每次修改都会修改版本号,每次对比的时候不仅对比值,还要对比版本号来保证数据没被修改。 (2) 自旋时间长导致开销大 * 问题描述:自旋 CAS 如果长时间不成功,会给 CPU 带来非常大的执行开销。 * 解决办法:如果JVM能支持处理器提供的 pause 指令那么效率会有一定的提升,pause 指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使 CPU 不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation:内存顺序冲突一般是由伪/假共享引起,假共享是指多个 CPU 同时修改同一个缓存行的不同部分而引起其中一个CPU的操作无效,当出现这个内存顺序冲突时,CPU必须清空流水线)而引起 CPU 流水线被清空(CPU pipeline flush),从而提高 CPU 的执行效率。 通过本篇博文,对原子包java.util.concurrent.atomic下的AtomicInteger类进行了分析,其他的类也比较类似,都是底层采用了CAS机制完成各种操作。也学习了CAS的原理和存在的问题以及解决办法。 更多精彩内容,敬请扫描下方二维码,关注我的微信公众号【Java觉浅】,获取第一时间更新哦!一、概述
二、源码分析
1. 类的声明
public class AtomicInteger extends Number implements java.io.Serializable
2. 成员变量
//序列化标识id private static final long serialVersionUID = 6214790243416807050L; //Unsafe类的一个实例,提供一些不安全的操作的方法用于直接操作内存,一般不会在自己的程序中使用该类 //在这里主要用到其中的objectFieldOffset、putOrderedInt、compareAndSwapInt方法 private static final Unsafe unsafe = Unsafe.getUnsafe(); //value成员属性的内存地址相对于对象内存地址的偏移量 private static final long valueOffset; ////初始化valueOffset,通过unsafe.objectFieldOffset方法获取成员属性value内存地址相对于对象内存地址的偏移量 static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } //int的值,volatile修饰,保证线程之间的可见性 private volatile int value;
@CallerSensitive public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } }
3. 构造函数
//int参数类型的构造函数 public AtomicInteger(int initialValue) { value = initialValue; } //无参构造函数,初始值是0 public AtomicInteger() { }
4. 其他方法
/** * 获取int值 */ public final int get() { return value; } /** * 设为指定值 */ public final void set(int newValue) { value = newValue; } /** * 最终设为指定值,但其它线程不能马上看到变化,会延时一会 */ public final void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } /** * 以原子方式设置为给定值,并返回旧值 */ public final int getAndSet(int newValue) { //乐观锁,非阻塞同步方式,循环调用compareAndSet,也就是自旋,直到成功 for (;;) { int current = get(); //CAS操作,期待值current与内存中的值比较,相等的话设为newValue值 //否则下个循环,调用get()获取current值,继续执行CAS操作直到成功 if (compareAndSet(current, newValue)) return current; } } /** * CAS操作,现代CPU已广泛支持,是一种原子操作; * 简单地说,当期待值expect与valueOffset地址处的值相等时,设置为update值 */ public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } /** * 弱比较 */ public final boolean weakCompareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } //调用unsafe.getAndAddInt方法进行数值操作 public final int getAndDecrement() { return unsafe.getAndAddInt(this, valueOffset, -1); } //调用unsafe.getAndAddInt方法进行数值操作 public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta); } //调用unsafe.getAndAddInt方法进行数值操作 public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } //调用unsafe.getAndAddInt方法进行数值操作 public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1; } //调用unsafe.getAndAddInt方法进行数值操作 public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta; } /** * 原子操作,自增,返回旧值 */ public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } } /** * 原子操作,自减,返回旧值 */ public final int getAndDecrement() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return current; } } /** * 原子操作,加上一个数,返回旧值 */ public final int getAndAdd(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return current; } } /** * 原子操作,自增,返回新值 */ public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } } /** * 原子操作,自减,返回新值 */ public final int decrementAndGet() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return next; } } /** * 原子操作,加上一个数,返回新值 */ public final int addAndGet(int delta) { for (;;) { int current = get(); int 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 Integer.toString(get()); } public int intValue() { return get(); } public long longValue() { return (long)get(); } public float floatValue() { return (float)get(); } public double doubleValue() { return (double)get(); } }
5. getAndAddInt()方法
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
6. CAS机制原理
7. CAS的优势
8. CAS存在的问题
三、总结
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算