原子更新与Unsafe操作

推荐阅读

当一个程序需要更新一个变量的时候,如果多个线程同时更新此变量,那么最终的结果可能无法得到预期的结果。比如 多个线程一起自增一个变量,因为线程之间存在本地缓存,那么更新的时候就会出现与预期不一致的结果。

Atomic 系列


通常我们需要使用Synchronized关键字或者Lock来避免临界区的资源被多个线程同时更新,这样的话可以防止出现上面的情况。但从JDK1.5 开始,JUC 提供了Atomic系列的原子操作,提供了一种简单,高效线程安全的更新变量方式。Atomic 系列的原子操作类总共提供了10多个类,属于4种类型的操作类: 更新基本类型,更新数组类型,更新引用类型,更新属性字段。

  1. **基本类:**AtomicInteger、AtomicLong、AtomicBoolean;
  2. **引用类型:**AtomicReference、AtomicReference的ABA实例、AtomicStampedRerence、AtomicMarkableReference;
  3. **数组类型:**AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
  4. 属性原子修改器(Updater):AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

Unsafe 类型


上面提到 Atomic 操作类基本都是对Unsafe 类的再次封装,那么我们有必要了解一下Unsafe 的相关使用。Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。

public final class Unsafe {

   private Unsafe() { }

  @CallerSensitive
  public static Unsafe getUnsafe() {
    Class var0 = Reflection.getCallerClass();
    if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
      throw new SecurityException("Unsafe");
    } else {
      return theUnsafe;
    }
  }
    
    
// 判断类是不是引导类类加载器加载的
// 只要判断他的加载器是不是null,是的话就是引导类加载器加载的
  public static boolean isSystemDomainLoader(ClassLoader var0) {
    return var0 == null;
  }    
    

如同上面看到Unsafe 源码一样, UnSafe 是一个单例的示例对象,可以使用其静态方法 getUnsafe() 获取到实例对象,但需要注意的是 在获取的时候判断获取实例的类是不是引导类加载的类,如果不是则会报错 SecurityException。




那么我们可以怎么获取Unsafe 的实例对象呢?

  1. getUnsafe方法的使用限制条件出发,通过Java命令行命令-Xbootclasspath/a把调用Unsafe相关方法的类A所在jar包路径追加到默认的bootstrap路径中,使得A被引导类加载器加载,从而通过Unsafe.getUnsafe方法安全的获取Unsafe实例。
java -Xbootclasspath/a: ${path}   // 其中path为调用Unsafe相关方法的类所在jar包路径

  1. 通过反射获取单例对象theUnsafe。
private static Unsafe reflectGetUnsafe() {
    try {
      Field field = Unsafe.class.getDeclaredField("theUnsafe");
      field.setAccessible(true);
      return (Unsafe) field.get(null);
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return null;
    }
}


一般我们通过 方法2 来获取到Unsafe 的单实例对象。


Unsafe 方法API 主要有以下几类 :
image.png


本章的Atomic 实现主要使用的CAS (Compare And Swap)即比较并替换,实现并发算法时常用到的一种技术。CAS操作包含三个操作数——内存位置、预期原值及新值。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。我们都知道,CAS是一条CPU的原子指令(cmpxchg指令),不会造成所谓的数据不一致问题,Unsafe提供的CAS方法(如compareAndSwapXXX)底层实现即为CPU指令cmpxchg。


但由于Unsafe 类使Java语言拥有了类似C 语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe 类会使得程序出错的概率变大,使得Java 这种安全的语言变得不再“安全”,因此对Unsafe 的使用一定要慎重。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值