Java自定义cas操作

时间:2022-09-18 03:01:12

java Unsafe工具类提供了一个方法

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

这个就是一个cas操作,原子操作。比较var1, 在var2偏移即offset位置的值是否为var4。如果是var4,更新为var5,返回true。否则,不做更新返回false

最近,听同事说了cas用到项目里面,感觉高大上。学习了一下,包装了一个cas整型操作

import java.lang.reflect.Field;
import sun.misc.Unsafe;

/**
 * @Author: <guanxianseng@163.com>
 * @Description:
 * @Date: Created in : 2018/11/28 3:36 PM
 **/
public class GxfInteger {
  private sun.misc.Unsafe U;
  private long offset;
  private Integer value = 0;
  private static Object lock = new Object();

  public GxfInteger(int value) throws Exception {
    this.value = value;
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    U = (Unsafe) f.get(null);
    offset = U.objectFieldOffset(GxfInteger.class.getDeclaredField("value"));
  }

  public void increament(){
    value ++;
  }

  public void lockAdd(){
    synchronized (lock){
      value++;
    }
  }

  public void casIncreament(){
    boolean update = false;
    do{
      update = U.compareAndSwapObject(this, offset, value, value + 1);
    }while (!update);
  }

  public int getValue() {
    return value;
  }

  public void setValue(int value) {
    this.value = value;
  }
}

写了一测试类

public class GxfIntegerTest {

  public static void main(String[] args) throws InterruptedException, Exception {
    GxfInteger gxfInteger = new GxfInteger(0);
    int threadNum = 100;
    Runnable add = () -> {
      for(int i = 0; i < 10000; i++){
//        gxfInteger.increament();
        gxfInteger.casIncreament();
//        gxfInteger.lockAdd();
      }
    };
    long start = System.currentTimeMillis();

    Thread[] threads = new Thread[threadNum];
    for(int i = 0; i < threads.length; i++){
      threads[i] = new Thread(add);
    }
    for(int i = 0; i < threadNum; i++){
      threads[i].start();
    }
    for(int i = 0; i < threadNum; i++){
      threads[i].join();
    }
    System.out.println("time cost : " + (System.currentTimeMillis() - start));
//    Thread.sleep(10000);
    System.out.println("result: " + gxfInteger.getValue());
  }
}

这里可以通过cas实现,线程安全。cas有点就是不会有锁的开销,上下文切换。也有缺点,自旋浪费资源,不能对多个资源保证线程安全

这里需要注意两点

1. 使用反射获取Unsafe对象

2. 注意offset的获取