引言

这篇文章会从基本概念中入手,首先,从volatile关键字引出原子性的概念和Atomic包,然后,介绍Atomic在使用中的用到的CAS技术和遇到的ABA问题,最后,介绍Atomic的成员和例子

基本概念

一、volatile

用volatile修饰的变量,线程在每次修改变量的时候,都会读取变量修改后的值,可以简单的理解为volatile修饰的变量保存的是变量的地址。volatile变量具有synchronized的可见性,但是不具备原子性

  • 可见性:在多线程并发的条件下,对于变量的修改,其他线程中能获取到修改后的值
  • 原子性:在多线程并发的条件下,对于变量的操作是线程安全的,不会受到其他线程的干扰

volatile不是线程安全的,要使volatile变量提供理想的线程安全,必须同时满足下面两个条件

  • 对变量的写操作不依赖于当前值
  • 该变量没有包含在具有其他变量的不变式中

比如增量操作(x++)看上去类似一个单独操作,实际上它是一个由[读取-修改-写入]操作序列组成的组合操作,必须以原子方式执行,而volatile不能提供必须的原子特性。实现正确的操作,应该使x的值在操作期间保持线程安全,而volatile变量无法实现这点

然而,Java提供了java.util.concurrent.atomic.*包下的变量或引用,让变量或对象的操作具有原子性,在高并发的情况下,依然能保持获取到最新修改的值,常见的有AtomicBooleanAtomicReference

  • volatile原理:对于值的操作,会立即更新到主存中,当其他线程获取最新值时会从主存中获取
  • atomic原理:对于值的操作,是基于底层硬件处理器提供的原子指令,保证并发时线程的安全

二、Atomic

Atomic的包名为java.util.concurrent.atomic。这个包里面提供了一组原子变量的操作类,这些类可以保证在多线程环境下,当某个线程在执行atomic的方法时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个线程执行

三、CAS

1、CAS简介

CAS指的是现代CPU广泛支持的一种对内存中的共享数据进行操作的一种特殊指令。这个指令会对内存中的共享数据做原子的读写操作。在Java并发应用中通常指CompareAndSwapCompareAndSet,即比较并交换,是实现并发算法时常用到的一种技术。java.util.concurrent包中借助CAS实现了区别于synchronized同步锁的一种乐观锁。乐观锁就是每次去取数据的时候都乐观的认为数据不会被修改,因此这个过程不会上锁,但是在更新的时候会判断一下在此期间的数据有没有更新

2、CAS思想

CAS有三个参数,当前内存值V、旧的预期值A、即将更新的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false

3、CAS优缺点

  1. 系统在硬件层面保证了CAS操作的原子性,不会锁住当前线程,它的效率是很高的。但是在并发越高的条件下,失败的次数会越多,CAS如果长时间不成功,会极大的增加CPU的开销,因此CAS不适合竞争十分频繁的场景
  2. CAS只能保证一个共享变量的原子操作,对多个共享变量操作时,无法保证操作的原子性,这时就可以用锁,或者把多个共享变量合并成一个共享变量来操作。JDK提供了AtomicReference类来保证引用对象的原子性,可以把多个变量放在一个对象里来进行CAS操作

四、ABA

CAS在操作值的时候检查值是否已经变化,没有变化的情况下才会进行更新。但是如果一个值原来是A,变成B,又变成A,那么CAS进行检查时会认为这个值没有变化,但是实际上却变化了。ABA问题的解决方法是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A就变成1A-2B-3A。JDK提供了AtomicStampedReference来解决ABA问题

Atomic成员

Atomic成员分为四大块

  1. 原子方式更新基本类型
  2. 原子方式更新数组
  3. 原子方式更新引用
  4. 原子方式更新字段

一、原子方式更新基本类型

  • AtomicBoolean:原子更新布尔类型
  • AtomicInteger:原子更新整型
  • AtomicLong:原子更新长整型

简单的看下AtomicInteger提供的方法

方法名 方法作用
get() 直接返回值
set(int) 设置数据(注意这里是没有原子性操作的)
getAndIncrement() 以原子方式将当前值加1,相当于线程安全的i++操作
incrementAndGet() 以原子方式将当前值加1,相当于线程安全的++i操作
getAndDecrement() 以原子方式将当前值减1,相当于线程安全的i–操作
decrementAndGet() 以原子方式将当前值减1,相当于线程安全的–i操作
getAndSet(int) 设置指定的数据,返回设置前的数据
addAndGet(int) 增加指定的数据,返回增加后的数据
getAndAdd(int) 增加指定的数据,返回变化前的数据
lazySet(int) 仅仅当get时才会set
compareAndSet(int, int) 比较源数据和期望数据(参数一),若一致,则设置新数据(参数二)到源数据中并返回true,否则返回false

以AtomicInteger为例

public class Main {static AtomicInteger ai = new AtomicInteger(1);public static void main(String[] args) {//先获取,再自增System.out.println(ai.getAndIncrement());//先自增,再获取System.out.println(ai.incrementAndGet());//增加一个指定值,先add,再getSystem.out.println(ai.addAndGet(5));//增加一个指定值,先get,再setSystem.out.println(ai.getAndSet(5));}
}

输出

1
3
8
8

二、原子方式更新数组

  • AtomicIntegerArray:原子更新整型数组里的元素
  • AtomicLongArray:原子更新长整型数组里的元素
  • AtomicReferenceArray:原子更新引用类型数组里的元素

以AtomicIntegerArray为例

public class Main {static int[] valueArr = new int[]{1, 2};//AtomicIntegerArray内部会拷贝一份数组static AtomicIntegerArray ai = new AtomicIntegerArray(valueArr);public static void main(String[] args) {ai.getAndSet(0, 3);//不会修改原始数组valueSystem.out.println(ai.get(0));System.out.println(valueArr[0]);}
}

输出

3
1

三、原子方式更新引用

  • AtomicReference:原子更新引用类型
  • AtomicReferenceFieldUpdater:原子更新引用类型里的字段
  • AtomicMarkableReference:原子更新带有标记位的引用类型

以AtomicReference为例

public class Main {public static AtomicReference<User> atomicUserRef = new AtomicReference<User>();public static void main(String[] args) {User user = new User("Jack", 22);User updateUser = new User("Rose", 20);atomicUserRef.set(user);atomicUserRef.compareAndSet(user, updateUser);System.out.println(atomicUserRef.get().getName());System.out.println(atomicUserRef.get().getOld());}static class User {private String name;private int old;public User(String name, int old) {this.name = name;this.old = old;}public String getName() {return name;}public int getOld() {return old;}}
}

输出

Rose
20

四、原子方式更新字段

  • AtomicIntegerFieldUpdater:原子更新整型字段的更新器
  • AtomicLongFieldUpdater:原子更新长整型字段的更新器
  • AtomicStampedReference:原子更新带有版本号的引用类型

以AtomicIntegerFieldUpdater为例

public class Main {private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");public static void main(String[] args) {User user = new User("Hensen", 20);System.out.println(a.getAndIncrement(user));System.out.println(a.get(user));}public static class User {private String name;public volatile int old;//注意需要用volatile修饰public User(String name, int old) {this.name = name;this.old = old;}public String getName() {return name;}public int getOld() {return old;}}
}

输出

22
23

Java进阶——Java中的Atomic原子特性相关推荐

  1. Java基础到Java进阶——Java小白的历练之路------从0到1,开卷!

    Java小白的历练之路------从0到1 title: Java Essay date: 2022-09-07 08:58:32 tags: Java notes 写在前面: 免责声明:本笔记来源自 ...

  2. Java进阶——Java中的字符串常量池

    字符串常量池 JVM为了减少字符串对象的重复创建,其内部维护了一个特殊的内存,这段内存被成为字符串常量池(方法区中).实际上还有整型常量池.浮点型常量池等等.字符串常量池存放的是对象的引用,而不是对象 ...

  3. Java进阶——Java面向对象编程(2)

    相信大部分学习的小朋友大朋友都有为这个知识点头疼,我也是呀,刚开始看到这个知识点,哎呀什么是重写呀,什么是重载呀,他们俩好像没什么区别呀?今天,本灯通过一篇博文,与大家细细地讨论"重写与重载 ...

  4. Java入门-Java学习路线课程面试篇:取商 / 和取余(模) % 符号的使用

    本博客地址 | GitHub | 更多资源免费下载 取商 / 和取余(模) % 符号的使用 文章目录 1. / % 最容易出错的演示案例 2. 运行结果: 1. / % 最容易出错的演示案例 pack ...

  5. Java并发编程中的若干核心技术,向高手进阶

    来源:http://www.jianshu.com/p/5f499f8212e7 引言 本文试图从一个更高的视角来总结Java语言中的并发编程内容,希望阅读完本文之后,可以收获一些内容,至少应该知道在 ...

  6. java中的Atomic类

    文章目录 问题背景 Lock 使用Atomic java中的Atomic类 问题背景 在多线程环境中,我们最常遇到的问题就是变量的值进行同步.因为变量需要在多线程中进行共享,所以我们必须需要采用一定的 ...

  7. 多线程编程进阶——Java类库中的锁

    在Java多线程中,可以使用synchronized关键字来实现线程之间同步互斥,在JDK1.5以后,Java类库中新增了Lock接口用来实现类似的锁功能.下面会逐一介绍关于Java类库中所提供的锁功 ...

  8. java进阶复习资料(参考网站中较全)

    1.迭代器Iterator为集合而生,专门实现集合遍历,该接口有三个方法,分别是____.____.____ hasNext() : next():remove(): 2.抽象方法只能定义在_____ ...

  9. Java中有些好的特性(一):静态导入

    首先,请原谅我用了一个很土,很有争议的标题.小弟才思枯竭,实在想不出来什么文雅的了,抱歉~~ 前言 换了东家后,从一个死忠C# Fans摇身一变,客串了一把Java程序员,可能是受老赵的<Why ...

最新文章

  1. Python使用matplotlib绘制透明背景的可视化图像并保存透明背景的可视化结果(transparent background)
  2. CSS浏览器兼容问题集-第四部分
  3. 交付铁三角的故事之兵戎相见
  4. 天池-街景字符编码识别5-模型训练与验证
  5. 二进制部署Kubernetes-v1.14.1集群
  6. Java分布式服务框架Dubbo初探(待实践)
  7. 利用Hownet进行语义相似度计算的类(
  8. 《寄生虫》横扫奥斯卡,Python告诉你这部电影到底好在哪里?
  9. mdx 医学词典_有没有专门医学英语词典app?
  10. sqlmap运行mysql命令_sqlmap命令总结
  11. html拾色器没效果,用html和js写一个拾色器
  12. 独立开发变现周刊(第44期):12岁的小男孩在9个小时内NFT卖了40万美元!
  13. 数仓--拉链表实战⭐⭐⭐⭐⭐
  14. origin作统计图(两个x正轴,一个y轴效果)
  15. 深度学习——模型调整
  16. 魔兽地图编辑器触发器中功能函数里各种单位的含义
  17. 霸王之业服务器未响应,三国群英传霸王之业常见问题解答_三国群英传霸业之业新人必看知识_3DM手游...
  18. GCT考试之考试结果
  19. 【SAP】公司代码与采购组织的分配关系
  20. swf to html5 movie maker,SWF to Video Converter Pro(Flash转换视频格式)

热门文章

  1. NYOJ-6-喷水装置(一)
  2. 容器组件(Container)
  3. 中国联通在宽带市场无力反击,衰退或将加剧
  4. 1分钟教你自己动手装系统
  5. 对计算机系统安全的威胁,浅谈计算机的常见安全威胁与应对策略
  6. 小东吖 之 java File类
  7. 微信支付接口-银行官方通道申请流程及材料
  8. java isalpha_isalpha()
  9. Docker宿主机异常重启后报Error response from daemon: OCI runtime create failed: container with id exists:xxx
  10. hasOwnProperty方法用法简介