由于java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,主要提供了以下功能:
•内存操作
•字段的定位与修改
•挂起与恢复
•CAS操作(乐观锁)
1.内存操作:
类中提供的3个本地方法allocateMemory、reallocateMemory、freeMemory分别用于分配内存,扩充内存和释放内存,与C语言中的3个方法对应.
2.字段的定位与修改:
可以定位对象某字段的内存位置也可以修改对象的字段值,即使它是私有的.
3.挂起与恢复
将一个线程进行挂起是通过park方法实现的,调用 park后,线程将一直阻塞直到超时或者中断等条件出现;unpark可以终止一个挂起的线程,使其恢复正常;整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。
4.CAS操作(乐观锁)
首先介绍一下什么是Compare And Swap(CAS)?简单的说就是比较并交换!
CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。
如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。
CAS 有效地说明了:
“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”
Java并发包(java.util.concurrent)中大量使用了CAS操作,涉及到并发的地方都调用了sun.misc.Unsafe类方法进行CAS操作,在Unsafe中是通过compareAndSwapXXX方法实现的。方法如下:
知识点:
1.Unsafe类java无法直接调用,只有操作系统底层才能使用;
代码演示:
import java.lang.reflect.Field;
import java.util.Arrays;
import sun.misc.Unsafe;
public class UseUnsafe {
private static int byteArrayBaseOffset;
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
/*Unsafe类java无法直接调用,只有操作系统底层才能调用;
* 通过反射强制调用java.lang.reflect.Field,获取Unsafe类(虽然无法直接调用,但是可以强制获取);
* 需要自己import sun.misc.Unsafe进来,不自动提供;
* NoSuchFieldException(反射异常), SecurityException(权限异常), IllegalArgumentException(非法参数异常), IllegalAccessException(非法许可异常)
*/
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
//设置许可为true,即获取许可,必要步骤
theUnsafe.setAccessible(true);
Unsafe UNSAFE = (Unsafe) theUnsafe.get(null);
System.out.println(UNSAFE);
byte[] data = new byte[10];
System.out.println(Arrays.toString(data));
/* 调用一个本地方法,获得data数组中第一个元素的内存偏移地址;
* 即获得元素的实际物理偏移量;
*/
byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class);
System.out.println("byte[]数组的第一个元素的偏移地址"+byteArrayBaseOffset);
//设置指定的字节数组,修改其内存字段的位置,byteArrayBaseOffset基础的偏移量
//1.在data这个数组对象设置第一个位置为1
UNSAFE.putByte(data, byteArrayBaseOffset,(byte)1);
//2.在data这个数组对象设置第七个位置为8
UNSAFE.putByte(data, byteArrayBaseOffset+6,(byte)8);
System.out.println(Arrays.toString(data));
}