并发编程–原子操作CAS
1.预备概念
CAS:(compared and sweep)比较后进行交换,是一种乐观锁的设计思想。
synchronized:是以一种基于悲观锁的实现。
原子操作:不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换,在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段,需要硬件支持。
2.CAS原理
一.实现原理:
流程
比较后进行交换,当更新值的时候,带上旧值,如果旧值和当前变量的值相等,那就认为该数据没有被更其他线程操作过,再把新值赋值给该变量。
- 第一步当前线程通过旧值经过计算得到新值。
- compare内存中变量值和旧值,如果相等进入下一步。
- 旧值swap为新值。
带来的问题:
- ABA问题:利用CAS确保原子性,会带来ABA问题,所以常见的CAS一般带有版本号来确定是否有ABA问题。***cas(内存地址,旧值,新值)***。
- 开销问题:当旧值和内存中的值不相等,重新进入一次计算,可能导致死循环。
- 效率问题:一次CAS只能操作一个变量,当有多个变量需要组合更改。
利用CAS实现的原子操作类
更新基本类型的:AtomicBoolean AtomicInteger AtomicLong
更新数组的:AtomicIntegerArray AtomicLongArray
更新引用类型的:AtomicReference AtomicMarkableReference.
AtomicIntegerArray 测试:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicIntegerTest {
public static void main(String[] args) {
int [] integers = new int[]{1,2};
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(integers);
atomicIntegerArray.set(0,3);
System.out.println(atomicIntegerArray.get(0));
System.out.println(integers[0]);
}
}
运行结果:
3
1
~~~java
AtomicMarkedReference:通过boolean是否修改的方式保持原子性。
AtomicStampReference:通过版本戳的形式去保持原子更新,更新的版本可控。
测试代码:AtomicMarkedReferenceTest
package cn.enjoyedu.ch3;
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampReferenceTest {
public static void main(String[] args) throws InterruptedException {
AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
//声明一个引用
// AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);
AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicMarkableReference<AtomicReferenceTest.UserInfo>(userInfo,false);
//声明两个线程去修改
Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
thread.start();
thread.join();
Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
thread2.start();
}
static class ThreadModify1 extends Thread{
AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify1(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//获取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
boolean stamp = atomicStampedReference.isMarked();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
System.out.println(currentThread().getName()+b);
}
}
static class ThreadModify2 extends Thread{
AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify2(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//获取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
boolean stamp = atomicStampedReference.isMarked();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
System.out.println(currentThread().getName()+b);
}
}
}
运行结果:
Thread-1true
Thread-3false
测试代码:AtomicStampReferenceTest
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampReferenceTest {
public static void main(String[] args) throws InterruptedException {
AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
//声明一个引用
AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);
//声明两个线程去修改
Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
thread.start();
thread.join();
Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
thread2.start();
}
static class ThreadModify1 extends Thread{
AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify1(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//获取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
int stamp = atomicStampedReference.getStamp();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, stamp + 2);
System.out.println(currentThread().getName()+b);
}
}
static class ThreadModify2 extends Thread{
AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify2(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//获取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
int stamp = 0;
//atomicStampedReference.getStamp();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b= atomicStampedReference.compareAndSet(userInfo,deer,stamp,stamp+2);
System.out.println(currentThread().getName()+b);
}
}
}
运行结果:
Thread-1true
Thread-3false