上一篇 <<<Volatile的伪共享和重排序
下一篇 >>>Synchronized锁
CAS(Compare and Swap):比较并交换
优势: 非阻塞性,它对死锁问题天生免疫,使用无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销。
CAS(V,E,N)
- V表示要更新的变量(主内存)
- E表示预期值(本地内存)
- N表示新值
CAS底层源码
// 调用方法
atomic.incrementAndGet();
/*底层源码:*/
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;
}
/*以前的写法: */
public final int incrementAndGet() {
for (;;) {
//获取当前值
int current = get();
//设置期望值
int next = current + 1;
//调用Native方法compareAndSet,执行CAS操作
if (compareAndSet(current, next))
//成功后才会返回期望值,否则无线循环
return next;
}
}
CAS的ABA问题
CAS的ABA问题解决办法
方案1:AtomicStampedReference
/**
* 使用AtomicStampedReference可获取版本号信息
* 通过版本号可解决ABA问题
*/
atomicStampedReference = new AtomicStampedReference(INIT_NUM, 1);
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();
}
//(1)第一个参数expectedReference:表示预期值。
//(2)第二个参数newReference:表示要更新的值。
//(3)第三个参数expectedStamp:表示预期的时间戳。
//(4)第四个参数newStamp:表示要更新的时间戳。
if (atomicStampedReference.compareAndSet(value, UPDATE_NUM, 1, stamp + 1)) {
System.out.println(Thread.currentThread().getName() + " : 当前值为:" + atomicStampedReference.getReference() + " 版本号为:" + atomicStampedReference.getStamp());
} else {
System.out.println("版本号不同,更新失败!");
}
方案2:利用原子类手写CAS无锁
/**
* 定义AtomicInteger 修改为1表示该锁已经被使用该 修改为0表示为被使用
*/
private volatile AtomicInteger atomicInteger = new AtomicInteger(0);
private Thread lockCurrentThread;
/**
* 尝试获取锁
*
* @return
*/
public boolean tryLock() {
boolean result = atomicInteger.compareAndSet(0, 1);
if (result) {
lockCurrentThread = Thread.currentThread();
}
return result;
}
/**
* 释放锁
*
* @return
*/
public boolean unLock() {
if (lockCurrentThread != null && lockCurrentThread != Thread.currentThread()) {
return false;
}
return atomicInteger.compareAndSet(1, 0);
}
Java中Unsafe实现cas无锁机制常用方法
- 获取unsafe实例
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
e.printStackTrace();
}
- cas操作
// o csa对象 offset内存偏移量 expected 预期值 x新值
public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x);
- objectFieldOffset获取内存偏移量
//获取内存偏移量
public native long objectFieldOffset(Field f);
- park操作
//park 是挂起当前线程 isAbsolute 为true 代表睡眠一段时自动唤醒 time是纳秒级别
public native void park(boolean isAbsolute, long time);
- unpark操作
//unpark 将此线程唤醒
public native void unpark(Object thread);
相关文章链接:
<<<多线程基础
<<<线程安全与解决方案
<<<锁的深入化
<<<锁的优化
<<<Java内存模型(JMM)
<<<Volatile解决JMM的可见性问题
<<<Volatile的伪共享和重排序
<<<Synchronized锁
<<<Lock锁
<<<AQS同步器
<<<Condition
<<<CountDownLatch同步计数器
<<<Semaphore信号量
<<<CyclicBarrier屏障
<<<线程池
<<<并发队列
<<<Callable与Future模式
<<<Fork/Join框架
<<<Threadlocal
<<<Disruptor框架
<<<如何优化多线程总结