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,线程切换