一、什么是CAS?
比较交换(cas )。 这是CPU同时原语。 其功能是判断内存中某个位置的值是否为期望值,如果是,则更新为新值,这个过程是原子性的。
1公共类案例{
2 publicstaticvoidmain (字符串[ ] args ) {
3 atomicintegeratomicinteger=newatomicinteger (5;
4
5系统. out.print (atomic integer.compareandset (5,2019 ) );
6 system.out.println (' the value are ' atomic integer.get );
7
8系统. out.print (atomic integer.compareandset (5,1024 ) );
9 system.out.println (' the value are ' atomic integer.get );
10 }
11 }
CAS同时原语在Java语言中是sun.misc.Unsafe类的各个方法。 通过调用Unsafe类的CAS方法,JVM可以实现CAS程序集指令。 这是完全依赖硬件的功能,通过它实现了原子操作。 此外,由于CAS是系统原语,因此原语属于操作系统术语的范畴,是一个由若干指令组成、完成某些功能的过程,原语的执行必须是连续的,在执行过程中不允许中断。 也就是说,CAS是原子命令,不会引起数据不匹配的问题。
二. Unsafe类
以原子整合子原子类为例。
1 publicclassatomicintegerextendsnumberimplementsjava.io.serializable {
2保密长时间服务版本=6214790243416807050 l;
3
4//setuptouseunsafe.compareandswapintforupdates
5私密性staticfinalunsafeunsafe=unsafe.get unsafe (;
6隐私保护长时间服务;
7
8静态{
9特里{
10 value offset=unsafe.objectfieldoffset
11 ) atomic integer.class.getdeclaredfield (' value );
12 ) catch(exceptionex ) thrownewerror ) ex; }
13 }
14
15私有电压int value;
16
17/.
18 }
2.1参数分析
UnSafe是CAS的核心类。 Java方法无法直接访问基础,因此必须从本地(native )方法进行访问。 UnSafe相当于可以直接操作特定内存数据的后门。 Unsafe类位于sun.misc包中,Java cas操作的执行依赖于Unsafe类的方法,因此内部方法操作可以像c指针一样直接操作内存。
注意: Unsafe类的所有方法都是用native限定的。 也就是说,Unsafe类的方法直接调用基本资源来执行相应的任务。
变量valueOffset是该变量在内存中的偏移地址。 这是因为Unsafe从内存偏移地址获取数据。
变量value由volatile限定,以确保多线程之间的可见性。
2.2方法实例分析
例如,假设AtomicInteger原子类的getAndIncrement ()。
1 /**
2 *如何等效于2 * AtomicInteger.java类的自填充
3 */
4公共final int getandincrement (
5 return unsafe.getandaddint (this,valueOffset,1 );
6 }
7
获取8 //Unsafe类指定的内存区域变量的值
9 publicnativeintgetintvolatile (objectvar 1,long var2);
10
11
12 /**
13 * Unsafe类的方法
14 * @param var1当前AtomicInteger对象
15 * @param var2变量在内存中的偏移地址
16 * @param var4变量的增量
17 *方法分析:
18 *首先调用getIntVolatile ()方法获取指定内存区域的变量值并将其存储在var5中。
19 *在执行增值操作之前,请再次从此地址获取值,并将其与var5进行比较。
20 *如果相同,则更新var5的值并返回true,反转后退出循环并返回相加后的值;
21 *如果不相同,返回false,继续循环直到更新成功,然后重新获得值
2*/
23 publicfinalintgetandaddint (objectvar 1、long var2、int var4) {
24 int var5;
25 do {
26 var5=this.getint volatile (var 1,var2);
27 ) while (! this.compareandswapint(var1、var2、var5、var5 var4);
28
29返回Var 5;
30 }
三. CAS的缺点
3.1周期时间越长,开销越大
如果CAS无法获取值,则CPU会产生很大的开销。
3.2只能保证一个共有变量的原子性
操作多个共有变量时,循环CAS不能保证操作的原子性,但在这种情况下用锁可以保证原子性。
3.3 ABA问题
CAS算法实现的一个重要前提是,需要取出存储器中的某一时刻的数据,并与当前时刻进行比较进行替换,在该时间差内数据会发生变化。
例如,假设一个线程one从内存位置v中取出了a。 此时,另一个线程two也从内存中取出a。 然后,线程two执行一些操作以将值更改为b,线程two将v位置的数据更改为a。 此时,线程one进行了CAS操作,发现内存中还有a,线程one的操作成功。
线程one的CAS操作成功,但并不意味着此过程没有问题。
解决ABA问题的是Java.util.concurrent.atomic.atomicstampedreference; 用带时间戳的原子引用类解决。