CAS 原理
unsafe类
CAS 比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么执行操作,否则就一直循环!
缺点:
- 循环会耗时
- 一次性只能保证一个共享变量的原子性
- ABA问题
如何解决ABA问题
乐观锁:操作数据时非常乐观,认为别人不会同时修改数据,只是在执行更新的时候判断此期间别人是否修改了数据 代表为CAS
悲观锁: 比较悲观,认为别人会修改数据,操作数据时把数据锁住,直到操作完成后才释放锁,操作期间别人不能修改数据 代表为synchronized
加版本号控制,引入原子思想,乐观锁
@Test
public void ABA(){
AtomicStampedReference<Integer> atomicReference = new AtomicStampedReference<Integer>(98,1);
// 值为98 版本号为1
int version = atomicReference.getStamp();
new Thread(()->{
System.out.println(atomicReference.compareAndSet(98, 100, version, version + 1));
System.out.println("a--->"+atomicReference.getReference()+" 版本"+atomicReference.getStamp());
System.out.println(atomicReference.compareAndSet(100, 98, atomicReference.getStamp(), atomicReference.getStamp() + 1));
System.out.println("a--->"+atomicReference.getReference()+" 版本"+atomicReference.getStamp());
},"线程a").start();
new Thread(()->{
System.out.println("正常的线程");
System.out.println(atomicReference.compareAndSet(98, 9999, version, version + 1));
System.out.println("b--->"+atomicReference.getReference()+" 版本"+atomicReference.getStamp());
},"线程b").start();
}
Integer的自动装箱机制和坑
可重入锁
又名递归锁,拿到大门的锁就相当于也拿到了里面小门的锁
package com.CAS;
import java.util.concurrent.TimeUnit;
public class keChongRu {
public static void main(String[] args) {
Phone p = new Phone();
new Thread(()->{
// TimeUnit.SECONDS.sleep(2);
p.sms();
},"A").start();
new Thread(()->{
p.sms();
},"B").start();
System.out.println("main");
}
}
class Phone{
public synchronized void sms(){
System.out.println(Thread.currentThread().getName()+"sms");
call();
}
public synchronized void call(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"call");
}
}
手动Lock版本
package com.CAS;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class keChongRu {
public static void main(String[] args) {
PhoneLock p = new PhoneLock();
new Thread(()->{
// TimeUnit.SECONDS.sleep(2);
p.sms();
},"A").start();
new Thread(()->{
p.sms();
},"B").start();
System.out.println("main");
}
}
//手动挡
//锁需要配对,不然会卡住
class PhoneLock{
Lock lock = new ReentrantLock();
public void sms(){
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"sms");
call();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void call(){
lock.lock();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"call");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
class Phone{
public synchronized void sms(){
System.out.println(Thread.currentThread().getName()+"sms");
call();
}
public synchronized void call(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"call");
}
}
自旋锁的实现
一直在那儿死等条件成立
package com.CAS;
import sun.awt.windows.ThemeReader;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
public class SpinLockPro {
// 引用类型 默认为null
private AtomicReference<Thread> atomicReference = new AtomicReference<>();
// 自定义加锁
public void mylock(){
Thread thread = Thread.currentThread();
while(!atomicReference.compareAndSet(null,thread)){
// System.out.println(thread+"等");
}
System.out.println(thread+" --->lock");
}
// 自定义解锁
public void myUnLock(){
Thread thread = Thread.currentThread();
while (!atomicReference.compareAndSet(thread,null)){
}
System.out.println(thread+"=====>解锁了");
}
public static void main(String[] args) {
SpinLockPro spinLockPro = new SpinLockPro();
new Thread(()->{
spinLockPro.mylock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
spinLockPro.myUnLock();
}
},"A").start();
new Thread(()->{
spinLockPro.mylock();
try {
System.out.println("B");
} catch (Exception e) {
e.printStackTrace();
} finally {
spinLockPro.myUnLock();
}
},"B").start();
}
}
死锁
产生死锁的条件
- 互斥:一个资源每次只能被一个进程使用
- 请求与保持:进程因请求资源而阻塞时,对已获得的资源保持不放
- 循环等待
- 不可剥夺:已获得的资源未使用完之前,不可剥夺
package com.CAS;
import java.util.concurrent.TimeUnit;
public class DeadLock implements Runnable {
private String l1;
private String l2;
public DeadLock(String l1,String l2){
this.l1= l1;
this.l2 = l2;
}
@Override
public void run() {
synchronized (l1){
System.out.println(Thread.currentThread().getName()+" lock:"+l1+" 想拿"+l2);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (l2){
System.out.println(Thread.currentThread().getName()+" lock:"+l2+" 想拿"+l1);
}
}
}
public static void main(String[] args) {
DeadLock d1 = new DeadLock("A","B");
DeadLock d2 = new DeadLock("B","A");
new Thread(d1,"大哥").start();
new Thread(d2,"王者").start();
}
}
死锁的排查
1.日志
2.查看堆栈信息
jps -l 找到运行文件进程号 类似ps -l
jstack 43496 打印堆栈信息