你好,游客 登录 注册 搜索
背景:
阅读新闻

JDK AtomicInteger 源码分析

[日期:2017-06-26] 来源:Linux社区  作者:jabnih [字体: ]

@(JDK)[AtomicInteger]

JDK AtomicInteger 源码分析

Unsafe

实例化

Unsafe在创建实例的时候,不能仅仅通过new Unsafe()或者Unsafe.getUnsafe()来获取,因为Java会进行安全校验,只有信任的代码,才能够获取实例。

@CallerSensitive
publicstatic Unsafe getUnsafe() {
    Class var0 = Reflection.getCallerClass();
    if(var0.getClassLoader() != null) {
        throw new SecurityException("Unsafe");
    } else {
        return theUnsafe;
    }
}

要达到上述对应的ClassLoader为空,只有通过BootStrapLoader来加载才可以。(可以通过bootclasspath实现)
java -Xbootclasspath:/usr/jdk1.7.0/jre/lib/rt.jar:. com.mishadoff.magic.UnsafeClient

  Unsafe里面有一个静态变量,theUnsafe,另一种方式就是通过反射来获取该实例。
private static final Unsafe theUnsafe;

Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);

避免初始化

可以使用allocateInstance方法来绕过构造方法的调用。

public class UnsafeDemo {

    privateUnsafeDemo() {
        throw new IllegalStateException("非法访问");
    }

    publicstaticvoidmain(String[] args)
        throws Exception {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
        System.out.println(unsafe.allocateInstance(UnsafeDemo.class));
    }
}

并发

  可以通过Unsafe. compareAndSwap方法来实现Lock-free数据结构。使用的时候一般都会采用while循环在等待(Spin Lock),以及volatile来对内存数据变更能及时反应出来,在JDK里面AtomicInteger等应用到了。

字段的偏移

可以通过unsafe.objectFieldOffset来获取类的字段偏移,一般可以和Unsafe. compareAndSwap结合来使用。
如:

valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"))
unsafe.compareAndSwapInt(this, valueOffset, expect, update)

AtomicInteger

字段变量

在AtomicInteger里面,主要通过使用CAS和volatile来实现。

public class AtomicInteger extends Number implements java.io.Serializable{
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // value字段的偏移,用于compareAndSwapInt方法
    private static final long valueOffset;

    // 这里volatile用于在并发的时候变更值,能够及时的反应到其它线程
    private volatile int value;
}

具体方法

getAndSet

publicfinalintgetAndSet(int newValue) {
    /* 这里就用到了循环来控制,直到成功,类似自旋锁的方式,在冲突不大的情况下,性能会得到比较好的提升,但是同时也会比较耗CPU,因为是在一直在尝试。同时,在冲突比较大的时候,建议还是使用Lock */
    for (;;) {
        int current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

compareAndSet/weakCompareAndSet

这两个方法,和上面的区别在于只会调用一次,那么就需要开发者考虑失败的情况。

publicfinalbooleancompareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

本文永久更新链接地址http://www.linuxidc.com/Linux/2017-06/145197.htm

linux
相关资讯       JDK AtomicInteger 源码  JDK AtomicInteger 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款