什么是CAS
CAS:比较当前工作内存中的值和主内存中的值
如果这个值是期望的,那么则执行操作
如果不是就一直循环
- 缺点:
- 循环会耗时
- 一次性只能保证一个共享变量的原子性
- ABA问题
Unsafe类
自旋锁例子:
unsafe的compareAndSwapInt问题
/**
* 1. 此方法不由Java语言实现
* 2. 该方法的作用是读取传入对象o
* 在内存中偏移量为offset位置的值
* 与期望值expected作比较
* 3. 相等就把x值赋值给offset位置的值,并返回true
* 4. 不相等,就取消复制,方法返回false
*/
public final native boolean compareAndSwapInt(Object o, // 原对象
long offset, // 地址偏移量
int expected, //期望地址偏移量
int x);
ABA问题
原子引用
解决ABA问题,引入原子引用,对应的思想是乐观锁
//初始值,初始版本号
AtomicStampedReference<Integer> reference = new AtomicStampedReference<Integer>(10,1);
new Thread(()->{
int stamp = reference.getStamp();
//期望值,更新值,期望版本号,更新后版本号
boolean b = reference.compareAndSet(10, 11, stamp, stamp + 1);
});
各种锁的理解
公平锁、非公平锁(默认)
公平锁:先来后到
非公平锁:可以插队
可重入锁
递归锁,即会获得该同步方法内的所有锁
如一个方法里用到另一个有锁的方法,则获得所有锁
其中注意,两个sync方法属于同一把锁
两个方法的lock属于两把锁
自旋锁
即不断尝试,直到成功为止
//自定义自旋锁
public class MySpinLock {
//默认是null
AtomicReference<Thread> atomicReference = new AtomicReference<>();
//加锁
public void myLock(){
Thread thread = Thread.currentThread();
//自旋锁
while (!atomicReference.compareAndSet(null,thread));
}
//解锁
public void myUnLock(){
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread,null);
}
}
死锁解决
- 在终端使用:
jps -l
定位进程号- 使用
jstack 进程号
找到死锁问题