欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

前面已经讲过了 2、valueOffs 昆山软件开发 et表示的是变量值在内存中的偏移地址

点击: 次  来源:宝鼎软件 时间:2017-05-31

原文出处: 五月的仓颉

Unsafe

简朴讲一下这个类。Java无法直接会见底层操纵系统,而是通过当地(native)要领来会见。不外尽量如此,JVM照旧开了一个后门,JDK中有一个类Unsafe,它提供了硬件级此外原子操纵。

这个类尽量内里的要领都是public的,可是并没有步伐利用它们,JDK API文档也没有提供任何干于这个类的要领的表明。总而言之,对付Unsafe类的利用都是受限制的,只有授信的代码才气得到该类的实例,虽然JDK库内里的类是可以随意利用的。

从第一行的描写可以相识到Unsafe提供了硬件级此外操纵,好比说获取某个属性在内存中的位置,好比说修改工具的字段值,纵然它是私有的。不外Java自己就是为了屏蔽底层的差别,对付一般的开拓而言也很少会有这样的需求。

举两个例子,例如说:

public native long staticFieldOffset(Field paramField);

这个要领可以用来获取给定的paramField的内存地点偏移量,这个值对付给定的field是独一的且是牢靠稳定的。再好比说:

public native int arrayBaseOffset(Class paramClass);
public native int arrayIndexScale(Class paramClass);

前一个要领是用来获取数组第一个元素的偏移地点,后一个要领是用来获取数组的转换因子即数组中元素的增量地点的。最后看三个要领:

public native long allocateMemory(long paramLong);
public native long reallocateMemory(long paramLong1, long paramLong2);
public native void freeMemory(long paramLong);

别离用来分派内存,扩充内存和释放内存的。

虽然这需要有必然的C/C++基本,对内存分派有必然的相识,这也是为什么我一直认为C/C++开拓者转行做Java会有优势的原因。

CAS

CAS,Compare and Swap即较量并互换,设计并发算法时常用到的一种技能,java.util.concurrent包全完成立在CAS之上,没有CAS也就没有此包,可见CAS的重要性。

当前的处理惩罚器根基都支持CAS,只不外差异的厂家的实现纷歧样而已。CAS有三个操纵数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V沟通时,将内存值修改为B并返回true,不然什么都不做并返回false。

CAS也是通过Unsafe实现的,看下Unsafe下的三个要领:

public final native boolean compareAndSwapObject(Object paramObject1, long paramLong, Object paramObject2, Object paramObject3);

public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2);

public final native boolean compareAndSwapLong(Object paramObject, long paramLong1, long paramLong2, long paramLong3);

就拿中间这个较量并互换Int值为例好了,假如我们不消CAS,那么代码大抵是这样的:

public int i = 1;
    
public boolean compareAndSwapInt(int j)
{
    if (i == 1)
    {
        i = j;
        return true;
    }
    return false;
}

虽然这段代码在并发下是必定有问题的,有大概线程1运行到了第5行正筹备运行第7行,线程2运行了,把i修改为10,线程切换归去,线程1由于先前已经满意第5行的if了,所以导致两个线程同时修改了变量i。

办理步伐也很简朴,给compareAndSwapInt要领加锁同步就行了,这样,compareAndSwapInt要领就酿成了一个原子操纵。CAS也是一样的原理,较量、互换也是一组原子操纵,不会被外部打断,先按照paramLong/paramLong1获取到内存傍边当前的内存值V,在将内存值V和原值A作较量,要是相等就修改为要修改的值B,由于CAS都是硬件级此外操纵,因此效率会高一些。

由CAS阐明AtomicInteger道理

java.util.concurrent.atomic包下的原子操纵类都是基于CAS实现的,下面拿AtomicInteger阐明一下,首先是AtomicInteger类变量的界说:

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

static {
 try {
    valueOffset = unsafe.objectFieldOffset
        (AtomicInteger.class.getDeclaredField("value"));
  } catch (Exception ex) { throw new Error(ex); }
}

private volatile int value;

关于这段代码中呈现的几个成员属性:

1、Unsafe是CAS的焦点类,前面已经讲过了

2、valueOffset暗示的是变量值在内存中的偏移地点,因为Unsafe就是按照内存偏移地点获取数据的原值的

3、value是用volatile修饰的,这长短常要害的

下面找一个要领getAndIncrement来研究一下AtomicInteger是如何实现的,好比我们常用的addAndGet要领:

public final int addAndGet(int delta) {
    for (;;) {
        int current = get();
        int next = current + delta;
        if (compareAndSet(current, next))
            return next;
    }
}
 public final int get() {
          return value;
 }

这段代码如安在不加锁的环境下通过CAS实现线程安详,我们不妨思量一下要领的执行:

1、AtomicInteger内里的value原始值为3,即主内存中AtomicInteger的value为3,按照Java内存模子,线程1和线程2各矜持有一份value的副本,值为3

2、线程1运行到第三行获取到当前的value为3,线程切换

3、线程2开始运行,获取到value为3,操作CAS比拟内存中的值也为3,较量乐成,修改内存,此时内存中的value改变例如说是4,线程切换