0
点赞
收藏
分享

微信扫一扫

并发编程-CAS无锁模式及ABA问题

上一篇 <<<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框架
<<<如何优化多线程总结

举报

相关推荐

0 条评论