每天进步一点点,大家好,我是大龄码农。我们今天讲解concurrent包的另一个子包atomic,这个包中都是原子类以及原子操作类。原子类以及原子操作就可以解决++这种非原子操作可能导致的线程同步问题在讲解volatile时说过,它只具有可见性,但不具有原子性,对于多线程中的++操作,必须使用关键字synchronized来保证线程同步,这种阻塞同步是一种悲观的并发策略。相对地,还有一种非阻塞同步的乐观并发策略,顾名思义,就是很乐观地认为别人不会和我抢,所以不加锁,只有在最后更新时才会判断。此时如果操作失败也不会阻塞,它会采取一些补偿机制,一般就是反复重试。在讲原子类之前,先介绍下Unsafe类,因为原子类的操作都是基于该类做的。Unsafe对象提供了非常底层操作内存和线程的方法,该类只提供了一个私有的无参构造方法。通过getUnsafe()静态方法获得Unsafe对象,然后调用它的CAS操作
说明:我们在程序中无法直接调用,会抛出异常CAS是Compare And Swap的缩写,是比较并交换的意思,它是这样一种原子操作:针对一个变量,首先比较它的内存值与某个期望值是否相同,如果相同,就给它赋一个新值。
以compareAndSwapInt为例,该方法提供四个参数:对象实例、内存偏移量、字段期望值、字段新值。该方法会针对指定对象实例中的相应偏移量的字段执行CAS操作。基础的知识讲完了,我们现在开始讲解原子类,由于atomic子包中的原子类的实现机理很类似,我们就挑选几个典型的原子类来进行分析。AtomicInteger的原子类型自增

说明:1、通过包装后,可以使得变量的操作是线程安全的2、被升级的变量有两个限制:
说明:stamp是版本,每次修改可以通过+1保证版本唯一性。这样就可以保证每次修改后的版本也会往上递增
实践一、Unsafe通过反射获取Unsafe对象
定义一个测试对象
定义Unsafe的操作方法
测试类
说明:1、通过底层方法compareAndSwapInt()更新字段的值2、调用系统提供的方法获取Unsafe时,不出意外地抛出异常二、ABA

说明:使用版本控制可以解决ABA的问题三、自定义锁知道了原子类的底层实现方法,我们可以模仿创建一个自己的锁


其他常用的方法简单看下API就行,不难理解。总结:1、介绍了原子类的基本知识2、介绍了原子类实现的底层知识3、用程序讲解了一些常用原子类的主要方法
希望大家一定要动手做一做,自己验证一下。需要代码的朋友,可以留下邮箱。
- CAS是一个不可分割的原子操作,并且其原子性是直接在硬件层面得到保障的。
- CAS是乐观锁的一种实现方式
- CAS是一种无锁算法,在没有线程被阻塞的情况下实现多线程之间的变量同步。
说明:使用的都是native方法,如果只通过名字猜,估计也能知道getIntVolatile()是获取内存中最新的值,只要compareAndSwapInt()方法不成功,就一直反复尝试直到成功。其他功能基本类似就不再重复了。
AtomicIntegerFieldUpdater可以对普通变量进行升级- 这个普通变量,只是偶尔需要一个原子get/set操作
- 这个变量是其他人定义的,我们无权将他定义为原子类型,只能对他进行临时升级
- 不支持被static修饰的变量
- 可见范围,由public修饰的变量,private不行
- Java8引入
- 高并发下LongAdder比AtomicLong效率高,本质还是空间换时间
- 竞争激烈的情况下,LongAdder会把不同线程对应到不同的Cell上进行修改,降低冲突的概率,是多段锁的理念,提高了并发性
- 循环长时间不成功会给CPU带来非常大的开销
- ABA问题
实践一、Unsafe通过反射获取Unsafe对象
测试结果如下
希望大家一定要动手做一做,自己验证一下。需要代码的朋友,可以留下邮箱。
本文采摘于网络,不代表本站立场,转载联系作者并注明出处:https://www.iotsj.com//kuaixun/3293.html