CAS:Compare And Swap 无锁

来源:互联网 发布:php相册源码 编辑:程序博客网 时间:2024/06/13 01:04

CAS3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class UnsafeTest{

    private static Unsafe unsafe

     static 

            try 

               //通过反射获取rt.jar下的Unsafe类 

               Fieldfield = Unsafe.class.getDeclaredField("theUnsafe"); 

               field.setAccessible(true); 

                unsafe =(Unsafe) field.get(null); 

           } catch (Exceptione) { 

               System.out.println("GetUnsafe instance occur error"+e); 

           

       

    public static void main(String[]args) throws Exception 

       

            Class clazz= Target.class

           Field[]fields = clazz.getDeclaredFields(); 

           System.out.println("fieldName:fieldOffset"); 

            for (Fieldf : fields) { 

               // 获取属性偏移量,可以通过这个偏移量给属性设置,偏移量固定不变的 

               System.out.println(f.getName()+ ":" + unsafe.objectFieldOffset(f)); 

           

           Targettarget = new Target(); 

           FieldintFiled  =  clazz.getDeclaredField("intParam") ; 

           int a=(Integer)intFiled.get(target) ; 

           System.out.println("原始值是:"+a); //当前线程执行到该地方获取到最新值

           /*intParam的字段偏移是12 原始值是3 我们要改为10

             将上步获取值和通过字段偏移量获取该属性在该对象中位置(该字段一般设置volatile原语保证该线程立即可见最新值),然后判断比较并赋值

              如果相同则赋值,否则不同就是被其它线程已更改,那么跳过不更新

            */

           System.out.println(unsafe.compareAndSwapInt(target,12, 3, 10)); 

           int b=(Integer)intFiled.get(target); 

           System.out.println("改变之后的值是:"+b); 

           //这个时候已经改为10,所以会返回false 

           System.out.println(unsafe.compareAndSwapInt(target,12, 3, 10)); 

           FieldstrParam  =  clazz.getDeclaredField("strParam") ; 

           Stringstra=(String)strParam.get(target) ; 

           System.out.println("改变之前的值是:"+stra); 

           System.out.println(unsafe.compareAndSwapObject(target,24, null, "5")); 

           Stringstrb=(String)strParam.get(target) ; 

           System.out.println("改变之后的值是:"+strb); 

            /*

               fieldName:fieldOffset

               intParam:12

               longParam:16

               strParam:24

               strParam2:28

                原始值是:3

               true

                改变之后的值是:10

               false

                改变之前的值是:null

               true

                改变之后的值是:5

            **/

       

   

   class Target{ 

      volatile  int intParam=3; 

      volatile  long longParam

       volatile String strParam

       volatile String strParam2

   

unsafe.compareAndSwapInt(this,valueOffset, expect, update);

类似:

if(this == expect) {

  this= update

 returntrue;

}else {

returnfalse;

}

那么问题就来了,成功过程中需要2个步骤:比较this== expect,替换this= updatecompareAndSwapInt如何这两个步骤的原子性呢? 参考CAS的原理。

CAS是一个CPU指令所以是原子操作native方法

 ABA问题。因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么ABA 就会变成1A-2B3A

0 0
原创粉丝点击