1, 传统synchronized 锁缺陷:
悲观: 如果没有获取到锁的情况下,会让当前的线程变为阻塞的状态,释放CPU
执行权,效率非常低。
同步中嵌套同步,可能会出现死锁。
乐观锁: 本质上没有锁,,没有死锁现象,而且效率也比较高,不会释放cpu
执行权,通过预期比较或者版本号控制。
cas无锁
CAS: Compare and Swap,翻译成比较并交换。 执行函数CAS(V,E,N)
CAS有3个操作数,内存值V,旧的预期值E,要修改的新值N。当且仅当预期值E和内存值V相同时,将内存值V修改为N,否则什么都不做。
![](https://img.haomeiwen.com/i12197462/47295330d915f59a.png)
![](https://img.haomeiwen.com/i12197462/0a1195c6dbc6c372.png)
1.Cas 是通过硬件指令,保证原子性
2.Java是通过unsafe jni技术
3.原子类: AtomicBoolean,AtomicInteger,AtomicLong 等使用 CAS 实现。
使用AtomicInteger实现自增
package com.taotao.metithread;
import java.util.concurrent.atomic.AtomicLong;
/**
*@author tom
*Date 2020/7/18 0018 21:22
*
*/
public class Test002 extends Thread{
private static AtomicLong atomicLong=new AtomicLong();
@Override
public void run() {
while (atomicLong.get()<10000){
long l=atomicLong.incrementAndGet();
System.out.println(Thread.currentThread().getName()+","+l);
}
}
public static void main(String[] args) throws InterruptedException {
Long starttime=System.currentTimeMillis();
Test002 t1=new Test002();
Test002 t2=new Test002();
t1.start();
// t2.start();
t1.join();
// t2.join();
Long end=System.currentTimeMillis();
System.out.println(end-starttime);
}
}
public final long getAndAddLong(Object var1, long var2, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
return var6;
}
Var6 就是为旧的预期值:0 E
Var1,var2 就是我们共享变量值:V
Var6+Var4 就是我们的新值N
如果Var6(E)==Var1,var2 (V) 则修改V为N;
AtimicLong 实现乐观锁:
111
package com.taotao.metithread;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.IntStream;
/**
*@author tom
*Date 2020/7/18 0018 21:55
*基于cas 实现乐观锁
*/
public class AtomicTrylock {
private AtomicLong atomicLong = new AtomicLong(0);
//设计锁 java aqs 持有同一把锁,持有人state 为0 没有线程持有锁,获取到锁state为1;
private Thread lockcutrrentThread;
/***
* 获取锁 将内存值改为1
* @return
*/
public boolean mayiktTryLock() {
//v=0 e=0 v==e v=1
//预期值,更新值
boolean result = atomicLong.compareAndSet(0, 1);
if (result) {
lockcutrrentThread = Thread.currentThread();
}
return result;
}
/**
* 释放锁 ji8ang内存值改为0
* @return
*/
public boolean mayiktUnlock() {
if(lockcutrrentThread !=null && lockcutrrentThread !=Thread.currentThread()){
return false;
}
boolean result = atomicLong.compareAndSet(1, 0);
return result;
}
public static void main(String[] args) {
AtomicTrylock atomicTrylock =new AtomicTrylock();
IntStream.range(1,10).forEach((i)-> new Thread(()->{
try {
boolean result=atomicTrylock.mayiktTryLock();
if(result){
System.out.println(Thread.currentThread().getName()+",获取锁成功");
}else {
System.out.println(Thread.currentThread().getName()+",或区域锁失败——");
}
}catch (Exception e){
e.printStackTrace();
atomicTrylock.mayiktUnlock();
}finally {
atomicTrylock.mayiktUnlock();
}
}).start());
}
}
Cas Aba的问题
Cas主要检查 内存值V与旧的预值值=E是否一致,如果一致的情况下,则修改。
这时候会存在ABA的问题:
如果将原来的值A,改为了B,B有改为了A 发现没有发生变化,实际上已经发生了变化,所以存在Aba问题。
解决办法:通过版本号码,对每个变量更新的版本号码做+1
解决aba问题是否大:概念产生冲突,但是不影响结果,换一种方式 通过版本号码方式。
![](https://img.haomeiwen.com/i12197462/f6a528d7cd86824c.png)
AtomicMarkableReference
(1)第一个参数expectedReference:表示预期值。
(2)第二个参数newReference:表示要更新的值。
(3)第三个参数expectedStamp:表示预期的时间戳。
(4)第四个参数newStamp:表示要更新的时间戳。
package com.taotao.metithread;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
*@author tom
*Date 2020/7/18 0018 22:43
*
*/
public class Test004 {
// 注意:如果引用类型是Long、Integer、Short、Byte、Character一定一定要注意值的缓存区间!
// 比如Long、Integer、Short、Byte缓存区间是在-128~127,会直接存在常量池中,而不在这个区间内对象的值则会每次都new一个对象,那么即使两个对象的值相同,CAS方法都会返回false
// 先声明初始值,修改后的值和临时的值是为了保证使用CAS方法不会因为对象不一样而返回false
private static final Integer INIT_NUM = 1000;
private static final Integer UPDATE_NUM = 100;
private static final Integer TEM_NUM = 200;
private static AtomicStampedReference atomicStampedReference = new AtomicStampedReference(INIT_NUM, 1);
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Integer value = (Integer) atomicStampedReference.getReference();
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName() + " : 当前值为:" + value + " 版本号为:" + stamp);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// value 旧值 内存中的值 UPDATE_NUM 修改的值
if (atomicStampedReference.compareAndSet(value, UPDATE_NUM, 1, stamp + 1)) {
System.out.println(Thread.currentThread().getName() + " : 当前值为:" + atomicStampedReference.getReference() + " 版本号为:" + atomicStampedReference.getStamp());
} else {
System.out.println("版本号不同,更新失败!");
}
}
}, "线程A").start();
}
}
线程A : 当前值为:1000 版本号为:1
线程A : 当前值为:100 版本号为:2
Process finished with exit code 0
网友评论