做网站 上海,网络设计的约束要素是什么,广州网站设计公司新闻,网站的功能目标目录
一.原子更新基本类型类
实现原理
二.原子更新数组
三.原子更新引用类型
四.原子更新字段类 Java从JDK1.5开始提供了J.U.C下的atomic包#xff0c;atomic包提供了一系列的操作简单#xff0c;性能高效#xff0c;并能保证线程安全的类去更新基本类型变量#xff0…目录
一.原子更新基本类型类
实现原理
二.原子更新数组
三.原子更新引用类型
四.原子更新字段类 Java从JDK1.5开始提供了J.U.C下的atomic包atomic包提供了一系列的操作简单性能高效并能保证线程安全的类去更新基本类型变量数组元素引用类型以及更新对象中的字段类型。
atomic包里的类基本都是使用 Unsafe 实现的包装类使用Unsafe提供的三个CAS方法结合死循环实现的也就是乐观锁。 一.原子更新基本类型类
我们Java中的基本数据类型是用的非常多的Atomic包针对基本数据类型提供了3个类使用原子的方式更新基本类型。
AtomicBoolean原子更新布尔类型AtomicInteger原子更新整型AtomicLong原子更新长整型
以上3个类提供的方法几乎一模一样所以这里只以AtomicInteger为例进行讲解。
int addAndGet(int delta)原子地将给定值与实例中的值AtomicInteger里的value相加并返回结果。boolean compareAndSet(int expect, int update)如果输入的数值等于预期值则以原子方式将该值设置为输入的值int getAndIncrement()以原子的方式将当前值1注意这里是返回增加之前的原有值void lazySet(int newValue)懒设置即最终会设置成newValue,使用lazySet设置值后可能导致其他线程在之后的一小段时间内还是可以读到旧的值这是基于性能方面考虑因为在多个CPU缓存间同步一个内存的代价是很昂贵的。int getAndSet(int newValue)以原子方式设置为newValue的值并返回旧值 实现原理
getAndIncrement() 是如何实现原子操作的呢让我们一起分析其实现原理。 可以看出该方法实际上是调用了unsafe实例的getAndAddInt方法unsafe实例的获取时通过UnSafe类的静态方法getUnsafe获取 Unsafe 是JDK提供的一个工具类里面有很多 native 方法即本地方法是 JVM 使用 C 帮我们实现的我们只要记住他提供了一些安全的操作方法是直接操作内存的。
unsafe.getAndAddInt(this,valueOffset,1) 方法中的三个参数
第1个 this 就是指我们当前操作的 AtomicInteger 对象第2个参数 valueOffset这是一个成员变量代表value成员属性的内存地址相对于对象内存地址的偏移量。这样就能根据对象的内存地址找到属性值的内存地址。第3个参数是1这个也好理解因为我们这个方法就是用来自增的嘛每次增加1是增量值。
我们接着往里看 这里使用了 do-while 循环其实也就是乐观锁非阻塞的同步方式一直尝试进行原子操作更新直到成功。
Atomic包提供了3种基本类型的原子更新但是Java的基本类型里还有 char、float和double等。那么问题来了如何原子的更新其他的基本类型呢Atomic包里的类基本都是使用Unsafe实现的让我们一起看一下Unsafe的源码。
/**
* 如果当前数值是expected则原子的将Java变量更新成x
* return 如果更新成功则返回true
*/
public final native boolean compareAndSwapObject(Object o,long offset , Object expected , Object x );
public final native boolean compareAndSwapInt(Object o , long offset , int expected, int x );
public final native boolean compareAndSwapLong(Object o , long offset , long expected ,long x );
通过代码我们发现Unsafe只提供了三种CAS方法
boolean compareAndSwapObject(Object o,long offset , Object expected , Object x );boolean compareAndSwapInt(Object o , long offset , int expected, int x );boolean compareAndSwapLong(Object o , long offset , long expected ,long x );
再看 AtomicBoolean 源码 它是先把Boolean转换成整型再使用 compareAndSwapInt 进行CAS所以原子更新char、float和double变量也可以用类似的思路来实现。
二.原子更新数组
通过原子的方式更新数组里的某个元素即操作数组元素是线程安全的Atomic包提供了以下3个类
AtomicIntegerArray原子更新整型数组里的元素AtomicLongArray原子更新长整型数组里的元素AtomicReferenceArray原子更新引用类型数组里的元素
上述几个类提供的方法几乎一样我们以AtomicIntegerArray类为例讲解其常用方法如下
int addAndGet(int i , int delta)以原子方式将输入值与数组中索引 i 的元素相加boolean compareAndSet(int i , int expect , int update)如果当前值等于预期值则以原子方式将数组位置i的元素设置成update值 三.原子更新引用类型
上面我们学会了如何原子更新基本类型但是我们平常使用最多的还是引用类型这个要如何更新呢Atomic包提供了以下3个类
AtomicReference原子更新引用类型 AtomicReferenceFieldUpdater原子更新引用类型里的字段 AtomicMarkableReference原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引用类型。构造方法是 AtomicMarkableReferenceV initialRefboolean initialMark
以上几个类提供的方法几乎一样所以此处我们仅以AtomicReference为例进行讲解AtomicReference的使用示例代码如下 其实现原理是依靠了 unsafe.compareAndSwapObject 方法。 四.原子更新字段类
如果需原子地更新某个类里的某个字段时就需要使用原子更新字段类Atomic包提供了以下3个类进行原子字段更新。
AtomicIntegerFieldUpdater原子更新整型的字段的更新器AtomicLongFieldUpdater原子更新长整型字段的更新器AtomicStampedReference原子更新带有版本号的引用类型。该类将整数值与引用关联起来可用于原子的更新数据和数据的版本号可以解决使用CAS进行原子更新时可能出现的ABA问题
要想原子地更新字段类需要两步
第一步因为原子更新字段类都是抽象类每次使用的时候必须使用静态方法newUpdater()创建一个更新器并且需要设置想要更新的类和属性。第二步更新类的字段属性必须使用 public volatile 修饰符
以上3个类提供的方法几乎一样此处仅以 AtomicIntegerFieldUpdater 为例进行讲解AtomicIntegerFieldUpdater的 示例代码如下