CAS
一、原子类
java.util.concurrent.atomic
二、没有CAS之前
三、使用CAS之后
四、CAS是什么?
1. 说明与原理
2.硬件基本保证
3.源码分析compareAndSet(int expect, int update)
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
五、CAS底层原理?如何知道,谈谈你对UnSafe的理解
1.UnSafe
2.我们知道i++线程不安全的,那atomicInteger.getAndIncrement()
3.源码分析
六、原子引用
七、CAS与自旋锁,借鉴CAS思想
1.自旋锁是什么
2.自己实现一个自旋锁SpinLockDemo
/**
* 题目:实现一个自旋锁,复习CAS思想
* 自旋锁好处:循环比较获取没有类似wait的阻塞
*
* 通过CAS操作完成自旋锁,A线程先进来调用lock方法,自己持有5秒钟,B随后进来发现
* 当前线程持有锁,所以只能通过自旋等待,知道A释放锁后B随后抢到。
*
*/
public class SpinLockDemo {
AtomicReference<Thread> atomicReference=new AtomicReference<>();
public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(()->{
spinLockDemo.lock();
try { TimeUnit.SECONDS.sleep(5); }catch (Exception e){e.getMessage();}
spinLockDemo.unLock();
},"A").start();
try { TimeUnit.SECONDS.sleep(1); }catch (Exception e){e.getMessage();}
new Thread(()->{
spinLockDemo.lock();
spinLockDemo.unLock();
},"B").start();
}
public void lock(){
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName()+" ---come in");
while (!atomicReference.compareAndSet(null,thread)){
}
}
public void unLock(){
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread,null);
System.out.println(Thread.currentThread().getName()+" ---task over,unLock...");
}
}
八、CAS缺点
1.循环时间长开销很大
2.ABA问题: 比较+版本号一起上
①ABA问题怎么产生的
②:版本号时间戳原子引用
AtomicStampedReference简单case
public class AtomicStampedDemo {
public static void main(String[] args) {
Book javaBook = new Book(1, "Java");
AtomicStampedReference<Book> stampedReference=new AtomicStampedReference<>(javaBook,1);
System.out.println(stampedReference.getReference()+" "+stampedReference.getStamp());
Book mysqlBook = new Book(2, "MySql");
boolean b;
b= stampedReference.compareAndSet(javaBook, mysqlBook, stampedReference.getStamp(), stampedReference.getStamp()+1);
System.out.println(b+" "+stampedReference.getReference()+ " "+stampedReference.getStamp());
b= stampedReference.compareAndSet(mysqlBook, javaBook, stampedReference.getStamp(), stampedReference.getStamp()+1);
System.out.println(b+" "+stampedReference.getReference()+ " "+stampedReference.getStamp());
}
}
ABADemo
public class ABADemo {
static AtomicInteger atomicInteger=new AtomicInteger(100);
public static void main(String[] args) {
new Thread(()->{
atomicInteger.compareAndSet(100,101);
atomicInteger.compareAndSet(101,100);
},"t1").start();
try { TimeUnit.SECONDS.sleep(1); }catch (Exception e){e.getMessage();}
new Thread(()->{
boolean b = atomicInteger.compareAndSet(100, 2023);
System.out.println(b +" "+ atomicInteger.get());
},"t1").start();
}
}
true 2023
public class ABADemo {
static AtomicInteger atomicInteger=new AtomicInteger(100);
static AtomicStampedReference<Integer> stampedReference=new AtomicStampedReference(100,1);
public static void main(String[] args) {
new Thread(()->{
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+" 首次版本号 "+stamp);
//等待1秒 保证t2线程获取到和我一样的版本号
try { TimeUnit.SECONDS.sleep(1); }catch (Exception e){e.getMessage();}
stampedReference.compareAndSet(100,101,stampedReference.getStamp(),stampedReference.getStamp()+1);
stampedReference.compareAndSet(101,100,stampedReference.getStamp(),stampedReference.getStamp()+1);
},"t1").start();
new Thread(()->{
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+" 首次版本号 "+stamp);
//等待2秒 保证t1线程发声ABA问题
try { TimeUnit.SECONDS.sleep(2); }catch (Exception e){e.getMessage();}
boolean b = stampedReference.compareAndSet(100, 2023,stamp,stampedReference.getStamp()+1);
System.out.println(b +" "+ stampedReference.getReference() + " "+stampedReference.getStamp());
},"t2").start();
}
}
t1 首次版本号 1
t2 首次版本号 1
false 100 3