在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