(1) 概念:CompareAndSet 一种无锁的原子算法,使用乐观锁, 如:版本控制,CAS可以保证一次的读-改-写操作是原子操作,在单处理器上该操作容易实现,但是在多处理器上实现就有点儿复杂了。
悲观锁:写(增删改)的操作多,读(查)的少 Lock
乐观锁:读的多,写的少
(2) 思想:给你一个期望值,与你现在的值比较,如果相等立即修改,反之不能修改什么也不做CAS(V,E,N)
(3)作用及优点:CAS实现稍微复杂,无锁,不存在阻塞,提高了效率,CPU的吞吐量,性能好
(4)缺点:CAS虽然高效地解决了原子操作,但是还是存在一些缺陷的,主要表现在三个方法:循环时间太长、只能保证一个共享变量原子操作、ABA问题。
public class CAS1{
private static volatile int m = 0;
private static AtomicInteger atomicI = new AtomicInteger (0);
public static void increase1(){
m++;//反编译javap -c 这里使用了3条指令,iconst_1、iadd、putstatic,CPU会时间片轮询所以会出现不一致问题
}
public static void increase2(){
atomicI .incrementAndGet();//反编译javap -c 这里使用了1条 invokevirtual 指令
}
public static void main(String[] args) throws Exception{
Thread[] t = new Thread[20];
for(int i = 0; i < 20; i++){
t[i] = new Thread(()->{
CAS1.increase1();
});
t[i].start();
t[i].join();//join方法加入 group main()//join线程有了交互性。就是让t[i]先执行
}
System.out.println(m);//小于20
Thread[] tf = new Thread[20];
for(int i = 0; i < 20; i++){
tf[i] = new Thread(()->{
CAS1.increase2();
});
tf[i].start();
tf[i].join();
}
System.out.println("atomic:"+atomicI.get());
}
}
unsafe——后门类,调用CPU指令
valueOffset——地址偏移量,有一个初始地址+地址偏移量=真实地址
value——要修改的值,要保证可见性所以使用volatile
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
var1——目标值
var2——期望值
var4——更改值
public final class Unsafe {
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {//通过JVM调用底层指令
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
}
就是用Lock和 cmpxchg指令来实现的
incrementAndGet()->unsafe->unsafe.cpp->汇编cmpxchg,用硬件去保证原子性
AbstractQueueSynchronizer 同步发生器 构建LOCK,封装性比较高,属于JUC包下,作用于子类定义非公共内部帮助类,写锁的时候的一个帮助器,提供获取锁,如:ReentrantLock重入锁也会用到AQS、ReadWriteLock、Condition
AQS定义两种资源共享方式:Exclusive(acquire独占方法,只有一个线程能执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。
CANCELLED——因中断、完成、退出队列
SIGNAL——节点的继任者被阻塞
CONDITION——条件阻塞
PROPAGATE——共享模式 头结点的状态
static final class Node {
/** Marker to indicate a node is waiting in shared mode */
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */
static final Node EXCLUSIVE = null;
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
公平锁
非公平锁
ReentrantReadWriteLock 实现了 ReadWriteLockReadWriteLock有两个方法 readLock() 返回读取锁、writeLock()返回写入锁
这里的读采用的是非锁的机制, 读取者优先或写入者优先强加给锁访问的排序。但是,它确实支持可选的公平策略。主要是读写分离
首先获取readLock(),读取之后释放读锁readLock.unLock(),然后去writeLock()获取写锁,wreteLock.lock()给写锁加锁,再要释放写锁之前我们要加上读锁readLock.lock() 最后进行释放写锁writeLock.unLock()这就是锁降级