Unsafe类的CAS

在FutureTask中使用到了大量Unsafe类的compareAndSwapObject方法

在遇到线程安全问题时,我们通常需要使用锁来解决问题。而其中分为悲观锁与乐观锁,java中的synchronize关键字使用的就是悲观锁,它完全排除其他线程操作的可能,让其他有可能操作的线程挂起,独占资源直至操作结束,释放锁。 虽然保证了安全,但是效率极低。

而CompareAndSwap则是一种乐观锁,它不排斥其他线程,每次赋值操作时会比对要操作的旧值是否与现值相等,如果相等再赋予新值。否则(说明有其他线程改变了)返回失败,调用线程可以再次尝试。

在java中要原子性的改变一个对象O的一个类变量v,需要使用到Unsafe类compareAndSwap函数,还提供了Object、int和long的三个重载函数

    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

    public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

拿compareAndSwapInt举例:

4个参数分别是

var1 对象O

var2 变量v在这个对象O中的地址偏移量, 实际用途就是和var1一起计算出 要赋值的那块地址的int*

var4 旧值 

var5 新值

CAS的C实现如下

int compare_and_swap (int* reg, int oldval, int newval) 
{
  ATOMIC();
  int old_reg_val = *reg;
  if (old_reg_val == oldval) 
     *reg = newval;
  END_ATOMIC();
  return old_reg_val;
}

这里不得不说到volatility关键字

这是同步锁的一个优化方案 但是它保证了同步的可见性,却无法保证原子性

比如一个i++操作 实际上在汇编上就分为 取值 +1 赋值操作 在赋值之前无法保证线程安全

所以这样的操作是非原子的


原子操作指的是在一步之内就完成而且不能被中断。原子操作在多线程环境中是线程安全的,无需考虑同步的问题。在java中,下列操作是原子操作:

  • all assignments of primitive types except for long and double 除了double和long的基本类型赋值操作 为什么这俩不行? 因为实际赋值是先赋值前32位 再赋值后32位 所以非线程安全
  • all assignments of references 引用的赋值此操作
  • all operations of java.concurrent.Atomic* classes     AtomicXxx这样的类的操作 封装了诸如CAS这样的操作
  • all assignments to volatile longs and doubles  volatile声明的double和long的赋值操作(为什么这里就可以了?)因为内部封装了synchronize锁
参考引用:

https://www.cnblogs.com/Mainz/p/3546347.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值