CAS
在了解CAS之前,我们要先要了解一下atomic(java.util.concurrent.atomic),为什么在jdk1.5开始引入了atomic包呢?
Atomic
1、为什么要使用Atomic类
在多线程和高并发环境中,我们经常会对一个int型的共享变量值进行+1或-1操作,例如:
int count = 0;
// ...
count ++;
但是这种写法,在多线程共同修改共享变量的情况下,会出现问题,导致实际值和预期值不符,即上面的代码是线程不安全的。因此我们需要实现线程的同步。通常的做法就是使用synchronized关键字修饰相关方法,或对代码块加锁。
package com.guigu.JMM;
import jdk.nashorn.internal.ir.CallNode;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author xff
* @createTime 2022/5/3 18:32
*
* volatile 是虚拟机提供的轻量级的同步机制 -->可见性,不保证原子性,禁止指令重排
* 低配版的synchronized
* jmm 内存模型, -->可见性(线程副本的变量更改通知主内存,可做到线程通信)
* 原子性,(不可分割,完整性,某个线程在运行,不能被打扰,同时成功,同时失败)
* 有序性
*
*
*/
class MyDate{
volatile int number=0; //初始值0 没有可见性 volatile 加了之后就可见了相当于锁syn....
//使用guc 的atomicInteger 保证原子性的方法
AtomicInteger atomicInteger = new AtomicInteger();
public void update(){
this.number=60; //更新值的函数
}
public void addPlusPlus(){ // 加了volatile关键字,验证不保证原子性
//加了synchronized 锁,才能保证原子性 但是太重量级
//那么如何解决呢? 使用guc 的atomicInteger
number++; //i++ 是三步做的操作
//拿到值, 做操作,写入主内存
}
public void addMydateAtomic(){
atomicInteger.getAndIncrement();
//相当于 i++
}
}
/**
* 下面验证可见性 (number没有加volatile 关键字可见性修饰
* main 主线程
* aaa 线程
* 刚开始共用 mydate 数据number aaa修改 主不可见
*
* 验证原子性 (添加了volatile)
*/
public class Volatile {
public static void main(String[] args) { //主线程
MyDate myDate = new MyDate();
//开多个线程 进行 number的相加
for (int i = 1; i <=20; i++) {
new Thread( //20个线程 ,一个线程调用 100次
() ->{
for (int j = 0; j < 1000; j++){
myDate.addPlusPlus();
myDate.addMydateAtomic();
}
},String.valueOf(i)).start();
}
//等待上面的线程执行完之后,主线程在做操作
while (Thread.activeCount()>2){
// 一个main,一个gc
Thread.yield(); //线程让步
}
System.out.println(Thread.currentThread().getName()+ " number "+myDate.number);