先写个测试demo,目的是引出CAS的作用!
/**
* @author TAO
* @description: 原子变量-CAS算法
* @date 2020/9/21 20:53
*/
public class TestAtomicDeme {
public static void main(String[] args) {
AtomicDemo ad=new AtomicDemo();
for (int i=0;i<10;i++){
new Thread(ad).start();
}
}
}
class AtomicDemo implements Runnable {
private int serialNumber = 0;
@Override
public void run() {
try {
Thread.sleep(300);
}catch (InterruptedException e){
}
System.out.println(getSerialNumber());
}
public int getSerialNumber() {
return serialNumber++;
}
public void setSerialNumber(int serialNumber) {
this.serialNumber = serialNumber;
}
}
这里++后还是出现了两个00,那么这就是线程并发出问题了,首先要知道++这个操作是分为三个步骤
1.先从主存中将共享变量serialNumber 读取到自己独立线程缓存中
2.将自己线程中独立内存中的值加一
3.将独立内存中的值写会到主存中
在并发的情况下++操作就会出现数据异常的问题,那么这时也就会出现内存可见性的问题,如JUC-volatile-内存可见性,就会想到使用volatile关键字修饰serialNumber 变量,那么这里是不行的,因为里++的操作涉及到原子性问题,而volatile不能保证原子性,这里++产生的问题其实和JUC-volatile-内存可见性是类似的,也就会独立线程的值修改了,但是还没来得及同步到主存中,其他线程就取到主存中的值,造成数据异常的问题,这里可以将private int serialNumber = 0;改为private volatile int serialNumber = 0;但是发现还是存在同样的问题!
在JDK1.5之后java.util.concurrent.atomic包下给我们提供了原子变量,这中原子变量其实也就类似于Integer这种包装类,如AtomicInteger这就是Integer的原子变量类型
1.在java.util.concurrent.atomic包下的原子变量中数据使用volatile来保证内存可见性
2…在java.util.concurrent.atomic包下的原子变量中数据使用CAS算法来保证原子性
CAS算法
CAS算法是操作系统/硬件对于并发操作共享数据的支持,我们的JVM也对CAS算法做了支持。
CAS包含三个操作数:
1.内存值 V
2.预估值 A
3.更新值 B
当且仅当V==A时,V=B,否则不做任何操作。
手写CAS伪代码
/**
* @description: 手写CAS伪代码
* @author TAO
* @date 2020/9/22 21:05
*/
public class TestCAS {
public static void main(String[] args) {
final CompareAndSwap cas=new CompareAndSwap();
for (int i=0;i<10;i++){
new Thread(new Runnable() {
@Override
public void run() {
int expectedValue=cas.get();
boolean b=cas.compareAndSet(expectedValue,(int)(Math.random()*101));
System.out.println(b);
}
}).start();
}
}
}
class CompareAndSwap{
private int value;
//获取内存中的值
public synchronized int get(){
return value;
}
//比较
public synchronized int compareAndSwap(int expectedValue,int newValue){
int oldValue=value;
if(oldValue==expectedValue){
this.value=newValue;
}
return oldValue;
}
//设置
public synchronized boolean compareAndSet(int expectedValue,int newValue){
return expectedValue==compareAndSwap(expectedValue,newValue);
}
}
使用原子变量后的代码
/**
* @author TAO
* @description: 原子变量-CAS算法
* @date 2020/9/21 20:53
*/
public class TestAtomicDeme {
public static void main(String[] args) {
AtomicDemo ad=new AtomicDemo();
for (int i=0;i<10;i++){
new Thread(ad).start();
}
}
}
class AtomicDemo implements Runnable {
//private int serialNumber = 0;
private AtomicInteger serialNumber = new AtomicInteger ();
@Override
public void run() {
try {
Thread.sleep(300);
}catch (InterruptedException e){
}
System.out.println(getSerialNumber());
}
public int getSerialNumber() {
return serialNumber.getAndIncrement();
}
public void setSerialNumber(int serialNumber) {
this.serialNumber = serialNumber;
}
}