java原子类

1、Java中无法直接操作一块内存区域 在JDK的工具类Unsafe是可以直接访问操作系统的内存 Unsafe的大部分API都是native的方法,Unsafe的不少方法中必须提供原始地址(内存地址)和被替换对象的地址,偏移量自己计算 对应的对象的一个属性的偏移量就是其对象的地址开始增加,增加的数就是这个filed的偏移量,AtomicInteger中的value属性对应的偏移量,就是对象地址+VALUE = value的地址
2、直接操作内存,速度快,在高并发的条件之下能够很好地提高效率,Unsafe提供api大致可分为内存申请释放操作、int.long.object的CAS操作、object对象读写和volatile读写object的field、偏移量的地址读写、读写内存屏障 操作等

CAS一般用于乐观锁 cas函数有3个参数 V E N 其中v代表变量 E原始值 N新值 拿原始值和新值做比较 如果一直则表明未被修改 则可以进行更新 反之则表明已被修改过 但是还存在一种情况就是 v已经被修改过一次 后来就改回了原值 这种情况下就是ABA问题
在AtomicStampedReference中维护了一个时间戳,对应的数值被修改时,除了更新数据本身外还要更新时间戳,对象值以及时间戳都必须满足期望值,写入才会成功

Atomic包里的类基本都是使用Unsafe下的CAS方法实现
原子更新基本类型
  使用原子的方式更新基本类型,Atomic包提供了以下3个类。
  (1)AtomicBoolean: 原子更新布尔类型。
  (2)AtomicInteger: 原子更新整型。
  (3)AtomicLong: 原子更新长整型。
  以上3个类提供的方法几乎一模一样,以AtomicInteger为例进行详解,AtomicIngeter的常用方法如下:
  (1)int addAndGet(int delta): 以原子的方式将输入的数值与实例中的值相加,并返回结果。
  (2)boolean compareAndSet(int expect, int update): 如果输入的值等于预期值,则以原子方式将该值设置为输入的值。
  (3)int getAndIncrement(): 以原子的方式将当前值加1,注意,这里返回的是自增前的值。
  (4)void lazySet(int newValue): 最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
  (5)int getAndSet(int newValue): 以原子的方式设置为newValue,并返回旧值。
  Atomic包里的类基本都是使用Unsafe下的CAS方法实现

原子更新数组
通过原子的方式更新数组里的某个元素,Atomic 包提供了以下 3 个类。
AtomicIntegerArray:原子更新整型数组里的元素。
AtomicLongArray:原子更新长整型数组里的元素。
AtomicReferenceArray:原子更新引用类型数组里的元素

Atomic包提供了以下三个类:
  (1)AtomicReference: 原子更新引用类型。 对应普通的对象引用,底层使用的是compareAndSwapObject实现CAS,比较的是两个对象的地址是否相等
  (2)AtomicReferenceFieldUpdater: 原子更新引用类型的字段。
  (3)AtomicMarkableReferce: 原子更新带有标记位的引用类型。
  这三个类提供的方法都差不多,首先构造一个引用对象,然后把引用对象set进Atomic类,然后调用compareAndSet等一些方法去进行原子操作,原理都是基于Unsafe实现,但AtomicReferenceFieldUpdater略有不同,更新的字段必须用volatile修饰

 

posted @ 2020-04-07 08:50  吴某1  阅读(166)  评论(0编辑  收藏  举报