赞
踩
CAS又称 自旋锁、无锁,是一种乐观锁
- AtomicInteger atomicInteger=new AtomicInteger();
- public void addAtomic(){
- atomicInteger.getAndIncrement();
- }
-
- // getAndIncrement方法 this是当前AtomicIntegr对象
- // valueOffset是内存偏移量/值
- // 1为自增量
- // Unsafe类的getAndAddInt方法,该Unsafe类是在jdk里的rt.jar包
- public final int getAndIncrement() {
- return unsafe.getAndAddInt(this, valueOffset, 1);
- }
-
-
-
- public final int getAndAddInt(Object var1, long var2, int var4) {
- int var5;
- do {
- //var1对象里的var2这个内存偏移量的值
- var5 = this.getIntVolatile(var1, var2);
- //var1 AtomicInteger 对象本身
- //var2 该对象值得引用地址,内存地址偏移量
- //var4 需要变动的数量 +1
- //var5 是用var1 var2 找出的主内存中真实的值
- //用该 对象当前的值与var5比较
- //如果相同,进行var5+var4并且返回true
- //如果不同,继续从主内存中取值然后 再比较,直到更新完成
- } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
- return var5;
- }
创建一个原子类对象 ( 默认初始化值为0 ) , 也可以传入定值 , 当我们使用CAS方法时 , 传入一个预期值 , 一个修改值 , 仅当预期值和当前对象 valueOffset的内存偏移量的值相同 , 就可以修改成功 , 前提是没有被其他的线程抢先一步进行比较并交换 , 否则就要继续读取最新的修改值 ( 变量可以使用 volatile关键字解决可见性问题 , 就是说 : 一个线程对共享变量的修改,能够及时的被其他线程看到 , 立刻同步最新数值 ) , 再继续的进行比较并交换这一操作 , 直到修改成功..... 这是比较并交换的源代码 : native为本地方法 , 底层用C 实现对操作系统的访问和操作 (Java不可以直接访问)
注意 : 这时线程B 还不一定就能修改成功 , 有可能还有其它线程抢夺的速度比它快 , 很快的将期望值 var5 进行了修改 , 线程B比较发现和期望值不匹配 , 因此线程B可能继续下去 , 直到比较成功 , 返回 ture 即可
何为原子性:原子就是最小的单位 , 不可分割的 , 就是指一个操作是不可中断的。即使是多个线程一起执行的时候 ,一个线程的操作一旦开始,执行的过程中不允许被中断 , 也就是说不会被其他线程干扰 , 直到执行完毕 , 不会造成数据不一致的问题 , 因此原子类使用 CAS 保证了并发情况下线程的安全性
1. Unsafe 这个类是Java底层的一个类 , 是 CAS 的核心类 , 相当于是一个后门 , 它存在于 sun.misc 包中 , Unsafe 类中的所有的方法都是被 native 关键字修饰的 , 被 native 修饰的方法为本地方法 , 底层是用 C 实现对操作系统的访问和操作 , 就比如调用 UnSafe 类中的 CAS 方法 , 它是通过操作系统的汇编指令来实现操作内存数据的 , 因为Java中 CAS 操作的执行依赖于Unsafe 类的方法
2. Unsafe 通过 对象的 valueOffset 内存偏移地址获取原始内存值 , 用当前工作内存值 (var1,var2) 和期望值 (var5) 进行比较判断是否能替换 , 一旦修改了 , 其他的线程一比较发现工作内存的值和期望值不一样 , 所以就无法操作了 , 只能继续获取新值 (getIntVolatile) , 继续比较 , 这样就保证了一次只能有一个线程在执行并且执行成功 , 就算不加锁 , 其他的线程也是进不来的 , 就无法操作 , 因此我们说 : 原子类可以不加 synchronized 就实现了原子性,保证了线程的安全
3. 被 volatile 修饰的变量 , 保证了线程的可见性 , 一旦被修改 , 就能及时的将数据反馈给其他线程 , 以供其他线程获取最新的值
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。