博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JUC解析-Atomic
阅读量:5937 次
发布时间:2019-06-19

本文共 3643 字,大约阅读时间需要 12 分钟。

介绍

路径:java.util.concurrent.atomic

功能:提供了java中的一些原子操作,包括基本类型,引用类型,数组等 包含的类:

  • AtomicBoolean/AtomicInteger等基本类型的原子操作
  • AtomicIntegerArray等一些基本类型数组的原子操作
  • AtomicIntegerFieldUpdater等一些对对象成员的原子操作
  • AtomicStampedReference等为了解决CAS中的ABA问题而引入的类的原子操作,在这里可以简单的当做一个寻常类看待。

Unsafe类

路径:sun.misc.Unsafe 介绍:Unsafe是用于在实质上扩展Java语言表达能力、便于在更高层(Java层)代码里实现原本要在更低层(C层)实现的核心库功能用的。这些功能包括裸内存的申请/释放/访问,低层硬件的atomic/volatile支持,创建未初始化对象等。它原本的设计就只应该被标准库使用,通俗的来讲,通过这个类可以让过jvm直接对内存进行操作,以达到高效的效果,我们在使用的时候可以把unsafe提供的接口当做一个原子操作来使用即可,不建议在应用中使用该类。

AtomicBoolean相关原子类

该类提供了基本类型的原子操作, 包括的成员方法主要为:

  1. get/set等基本的操作,java对于大多的基本类型赋值都是原子操作
  2. compareAndSet类型的操作,主要是通过调用unsafe.compareAndSet实现
  3. decrementAndGet等类型操作,该操作通过一种spinlock的方式来实现,该循环会一直执行,直到满足compareAndSet执行成功,代码:
for (;;) {    int current = get();        int next = current - 1;        if (compareAndSet(current, next))            return next;    }复制代码

在类中有两个比较迷惑的方法LazySet和weakCompareAndSet,简单的介绍下,

  1. LazySet可以保证原子性,但是在多线程环境下,对共享变量的修改不能保证对其他的线程立即可见
  2. weakCompareAndSet和compareAndSet的具体的实现是相同的,但是从文档中可以看到前者有两点不同:
  • 可能会出现虚假的失败,个人理解并不是说compareAndSet不会出现失败,而是对于这个函数在失败的时候可以进行重试,而前者直接抛出(没有具体验证过,如果有人知道具体的原理,欢迎批评指正)
  • 并不会提供排序的保证,就是说当一个线程看到一个通过weakCompareAndSet修改的原子变量时,它不被要求看到其他变量的修改,即便该变量的修改在weakCompareAndSet操作之前,这个跟具体的JMM模型相关.

AtomicIntegerArray

该类型的类主要是为一个T [] array数组提供原子的操作,其中T是具体的array类型.

原理:Arrays和Java别的对象一样,都有一个对象头,它是存储在实际的数据前面的。这个头的长度可以通过unsafe.arrayBaseOffset(T[].class)方法来获取到,这里T是数组元素的类型。数组元素的大小可以通过unsafe.arrayIndexScale(T[].class)方法获取到。这也就是说要访问类型为T的第N个元素的话,你的偏移量offset应该是arrayOffset+N*arrayScale,在Array相关的原子操作方法中都是通过CAS的方式对特定的内存地址的类型数据进行操作,其他的操作与上面介绍的相似,具体可以参考相关的源码.

AtomicIntegerFieldUpdater

该类型主要是通过反射和unsafe.objectFieldOffset的形式获取到类的特定成员变量的地址,然后通过CAS的方式对特定位置的成员变量进行原子的操作,具体的实现是在内部类AtomicIntegerFieldUpdaterImpl中实现,在AtomicIntegerFieldUpdater中提供了抽象的成员方法,其中在具体的实现类中还包含了一些类型的验证,具体实现可以参看相关源码.

AtomicMarkableReference

对一个特定的数据成员类型进行原子的操作,具体数据类型为

private static class Pair
{ final T reference; final boolean mark; private Pair(T reference, boolean mark) { this.reference = reference; this.mark = mark; } static
Pair
of(T reference, boolean mark) { return new Pair
(reference, mark); } } 复制代码

原理:与前面的类型类似,通过unsafe.getFieldOffset获取到成员变量的offset,然后通过CAS对该offset内存地址进行原子操作,不同的是compareAndSet类似的接口,他只有在满足reference和mark都相等的情况下才进行修改,具体如下:

public boolean compareAndSet(V  expectedReference,                                 V  newReference,                                 boolean expectedMark,                                 boolean newMark) {        Pair
current = pair; return expectedReference == current.reference && expectedMark == current.mark && ((newReference == current.reference && newMark == current.mark) || casPair(current, Pair.of(newReference, newMark))); }复制代码

其他实现方式类似,具体参考源码

AtomicStampedReference类

该类处理的数据类型与AtomicMarkableReference类类似

private static class Pair
{ final T reference; final int stamp; private Pair(T reference, int stamp) { this.reference = reference; this.stamp = stamp; } static
Pair
of(T reference, int stamp) { return new Pair
(reference, stamp); } }复制代码

都是包含一个引用的成员,不同的是AtomicMarkableReference包含一个boolean类型成员,而AtomicStampedReference包含的是int类型成员,其他具体的实现方式类似。 AtomicStampedReference和AtomicMarkableReference类主要用来解决ABA的问题,对于一个全局变量A,初始状态线程1看到的是A(1)状态,后面线程2对A进行了修改转变为了A(2)状态,后面线程2又把A还原为了A(1)状态,这时候对于正常状态下的CAS是发现不了A已经经过了A(1)->A(2)->A(1)的变化的,但是通过这两个类就可以解决这个问题.

转载地址:http://jyttx.baihongyu.com/

你可能感兴趣的文章
springMVC---级联属性
查看>>
get和post区别
查看>>
crontab执行shell脚本日志中出现乱码
查看>>
cmd.exe启动参数说明
查看>>
《随笔记录》20170310
查看>>
网站分析系统
查看>>
一站式解决,Android 拍照 图库的各种问题
查看>>
从零开始来看一下Java泛型的设计
查看>>
Shell编程基础
查看>>
Shell之Sed常用用法
查看>>
3.1
查看>>
校验表单如何摆脱 if else ?
查看>>
JS敏感信息泄露:不容忽视的WEB漏洞
查看>>
让我们荡起双桨,Android 小船波浪动画
查看>>
分布式memcached服务器代理magent安装配置(CentOS6.6)
查看>>
Create Volume 操作(Part III) - 每天5分钟玩转 OpenStack(52)
查看>>
tomcat 8.0虚拟机配置文档
查看>>
pxc群集搭建
查看>>
JS中加载cssText延时
查看>>
常用的脚本编程知识点
查看>>