1.JAVA提供的操作内存类
sun.misc.Unsafe 操作类
此类在提升Java运行效率,很多Java基础类库都使用了此类以提升性能。
此类使Java拥有了像C语言的指针一样操作内存空间的能力,但是也使程序易错。
2.代码片段
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if(var0.getClassLoader() != null) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
getUnsafe()方法只能由ClassLoader == null的类调用,意味着调用这个方法的类是jdk中C代码加载的。
3.可以使用的方式
public static Unsafe getUnsafe() {
try {
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
// the unsafe instance
return (Unsafe) unsafeField.get(null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
使用反射可以获取到Unsafe操作类实例。
4.Unsafe基本操作
- 操作成员变量
public class Dog {
private String name;
private int age;
private long size;
}
public static void main(String[] args) throws Exception{
Unsafe unsafe = getUnsafe();
Dog dog = new Dog();
// 获取name属性偏移量
long nameOffset = unsafe.objectFieldOffset(Dog.class.getDeclaredField("name"));
unsafe.putObject(dog, nameOffset, "Rick");
// 获取age属性偏移量
long ageOffset = unsafe.objectFieldOffset(Dog.class.getDeclaredField("age"));
unsafe.putInt(dog, ageOffset, 11);
// 获取size属性偏移量
long sizeOffset = unsafe.objectFieldOffset(Dog.class.getDeclaredField("size"));
unsafe.putLong(dog, sizeOffset, 1000L);
System.out.println(dog);
}
- 操作数组
@Test
public void testArray(){
Unsafe unsafe = UnsafeMain.getUnsafe();
// pigs[]数组基本偏移量
int base = unsafe.arrayBaseOffset(Pig[].class);
// pigs[]数组的单位偏移量
int indexScale = unsafe.arrayIndexScale(Pig[].class);
// unsafe操作数组
Pig[] pigs = new Pig[8];
Pig pig = new Pig("Rick", 10, 800L);
unsafe.compareAndSwapObject(pigs, base + 5 * indexScale, null, pig);
System.out.println(pigs[5]);
}
- 内存操作
@Test
public void testMemory(){
Unsafe unsafe = UnsafeMain.getUnsafe();
// 申请内存
long index = unsafe.allocateMemory(1L);
// 设置内存
unsafe.putByte(index, (byte)-127);
// 根据地址获取数据
System.out.println(unsafe.getByte(index));
// 释放内存
unsafe.freeMemory(index);
}
- 多线程同步(包括锁机制,CAS操作等)
这部分包括了monitorEnter、tryMonitorEnter、monitorExit、compareAndSwapInt、compareAndSwap等方法。
其中monitorEnter、tryMonitorEnter、monitorExit已经被标记为deprecated,不建议使用。
Unsafe类的CAS操作可能是用的最多的,它为Java的锁机制提供了一种新的解决办法,比如AtomicInteger等类都是通过该方法来实现的。compareAndSwap方法是原子的,可以避免繁重的锁机制,提高代码效率。这是一种乐观锁,通常认为在大部分情况下不出现竞态条件,如果操作失败,会不断重试直到成功。
- 挂起与恢复
这部分包括了park、unpark等方法。
将一个线程进行挂起是通过park方法实现的,调用 park后,线程将一直阻塞直到超时或者中断等条件出现。unpark可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。
- 内存屏障
这部分包括了loadFence、storeFence、fullFence等方法。这是在Java 8新引入的,用于定义内存屏障,避免代码重排序。
loadFence() 表示该方法之前的所有load操作在内存屏障之前完成。同理storeFence()表示该方法之前的所有store操作在内存屏障之前完成。fullFence()表示该方法之前的所有load、store操作在内存屏障之前完成。
5.总结
一些JDK源码中使用了此Unsafe,如ConcurrentHashMap等。为之后的分析做准备。