一、原子类
java.util.concurrent.atomic下所有的类
二、没有用CAS之前
多线程下不使用原子类保证线程安全i++(基本数据类型)
package com.lori.juc2023.juc7;
public class casDemo1 {
volatile int number = 0;
//读取
public int getNumber(){
return number;
}
public synchronized void setNumber(){
number++;
}
}
三、使用CAS之后
多线程环境,使用原子类保证线程安全i++(基本数据类型)
package com.lori.juc2023.juc7;
import java.util.concurrent.atomic.AtomicInteger;
public class casDemo1 {
//AtomicInteger 既能保证原子性,又比加锁轻便
AtomicInteger atomicInteger = new AtomicInteger();
public int getAtomicInteger(){
return atomicInteger.get();
}
public void setAtomicInteger(){
//相当于i++
atomicInteger.getAndIncrement();
}
}
四、CAS是什么
1、原理
- compare and swap的缩写,中文翻译成比较并交换,实现并发算法时常用到的一种技术。
- 它包含三个操作数:内存位置、预期原值及更新值。
- 执行CAS操作的时候,将内存位置的值与预期原值比较:
- 如果相匹配,那么处理器会自动将该位置值更新为新值,
- 如果不匹配,处理器不做任何操作,多个线程同时执行CAS操作只有一个会成功。
举例说明: CAS有三个操作数,位置内存值V,旧的预期值A,要修改的更新值B。 当且仅当,旧的预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做,或者重来。 当它重来重试的这种行为称为---自旋
2、代码
package com.lori.juc2023.juc7;
import java.util.concurrent.atomic.AtomicInteger;
public class casDemo1 {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(5);
//看原始值是不是5,如果是5的话,将5修改为2023
boolean compareAndSet = atomicInteger.compareAndSet(5, 2023);
System.out.println(compareAndSet+"\t"+atomicInteger.get());
}
}
- 第一次执行结果:
- 如果加多一次修改
package com.lori.juc2023.juc7;
import lombok.val;
import java.util.concurrent.atomic.AtomicInteger;
public class casDemo1 {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(5);
//看原始值是不是5,如果是5的话,将5修改为2023
boolean compareAndSet = atomicInteger.compareAndSet(5, 2023);
System.out.println(compareAndSet+"\t"+atomicInteger.get());
boolean andSet = atomicInteger.compareAndSet(5, 2023);
System.out.println(compareAndSet+"\t"+atomicInteger.get());
}
}
3、硬件级别的保证
- CAS是JDK提供的非阻塞原子性操作,它通过硬件保证了此较-更新的原子性。它是非阻塞的且自身具有原子性,也就是说这玩意效率更高且通过硬件保证,说明这玩意更可靠。
- CAS是一条CPU的原子指令(cmpxchg指令),不会造成所谓的数据不一致问题,Unsafe提供的 CAS方法(如compareAndSwapxxx)底层实现即为CPU指令cmpxchg。
- 执行cmpxchg指令的时候,会判断当前系统是否为多核系统,如果是就给总线加锁,只有一个线程会对总线加锁成功,加锁成功之后会执行CAS操作,也就是说CAS的原子性实际上是CPU实现独占的,比起用synchronized重量级锁,这里的排他时间要短很多,所以在多线程情况下性能会比较好。
- var1:要操作的对象
- var2:标识要操作对象中属性地址的偏移量
- var4:表示要修改数据的期望值,也就是上一个版本拿到的值
- var5/var6:表示要修改为的新值
4、谈谈对Unsafe类的理解
- UnSafe类是CAS的核心类,由于Java犯法无法直接访问底层系统,需要通过本地方法native来访问,Unsafe相当于一个后门,基于该类可以直接操作特定的内存数据。Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法。
- 注意:UnSafe类中所有的方法都是native修饰的,也就是说UnSafe类中的方法都是直接调用操作系统底层资源执行相应的任务。
- 变量valueOffset,表示该变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址获取数据的
- 变量value用volatile修饰,保证了多线程之间的内存可见性
1、i++线程不安全,通过atomicInteger.getAndIncrement()保证线程安全
- CAS的全称是Compare-And-Swap,它是一条CPU并发原语
- 它的功能是判断内存某个位置是否为预期值,如果是则修改为新值,这个过程是原子的
- AtomicInteger类主要利用CAS+volatile和native方法来保证原子性,从而避免synchronized的高开销,执行效率大为提升。
CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
标签:JUC,CAS,AtomicInteger,内存,atomicInteger,public,compareAndSet From: https://blog.51cto.com/u_15410237/6362915