尝试班门弄斧地解答:
我最初对于Java语言的理解是:Java无法像C/C++那样使用指针操作内存,
其实Java语言偷偷地埋了个后门:sun.misc.Unsafe(Java9开始计划废弃),
这个类可以完成:
1、分配/重新分配/释放内存,(allocateMemory/reallocateMemory/freeMemory)
2、获得对象中某个属性/静态属性的在该对象中的偏移地址(objectFieldOffset/staticFieldOffset),
3、使用CAS等CPU的操作原语(compareAndSwapObject/compareAndSwapInt/compareAndSwapLong)
4、存取普通变量/volatile变量(putObject/getObject/putObjectVolatile/getObjectVolatile...)
5、线程挂起/恢复(park/unpark...)
6、内存屏障(loadFence/storeFence)
7、synchronized关键字中monitor对象锁定解锁(monitorEnter/monitorExit)
...
这些方法是Java很多底层功能的实现基石
1、NIO直接内存(Direct Memory,参见java.nio.DirectByteBuffer类)
2、大部分Unsafe类中的方法都需要一个类型为long的offset参数:
eg:
public native Object getObject(Object obj, long offset);
public final native boolean compareAndSwapInt(obj, offset, expect, update);
3、可用于实现基于CAS的乐观锁等操作
4、存取变量/volatile变量
5、java.util.concurrent.locks.LockSupport类中park/unpark系列方法实现的基础,LockSupport又是J.U.C实现的基础,用以实现线程挂起/恢复
6&7、还需要结合JVM才能彻底明白,底层的东西,自己也半吊子,就省略了
再多插一句:
sun.misc.Unsafe类的静态工厂方法比较有意思:
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
getUnsafe方法会验证类加载器,只有启动类加载器加载的类才可以调用Unsafe.getUnsafe方法,
自己写的类由于是应用(系统)类加载器加载的就会抛异常:SecurityException
此举显然是JDK开发者不希望应用开发者调用Unsafe类中的方法,毕竟这个类功能太过强大也太过底层,
使用不当是有很大风险的,当然我们可以使用Java黑魔法————反射拿到Unsafe实例
我提供两种反射思路拿到Unsafe实例:
// 获取Unsafe类中属性"theUnsafe"获取实例
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
System.out.println(unsafe);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
// 通过私有构造器创建实例
try {
Constructor<Unsafe> c = Unsafe.class.getDeclaredConstructor();
c.setAccessible(true);
Unsafe unsafe = c.newInstance();
System.out.println(unsafe);
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
有了Unsafe实例,我们就可以玩了:
public class CASDemo {
private static Unsafe unsafe;
private int count = 0;
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
CASDemo instance = new CASDemo();
// 使用反射API获取count变量的Field
Field countVariableField = CASDemo.class.getDeclaredField("count");
// 使用Unsafe类中objectFieldOffset方法获取CASDemo类中count属性的偏移地址:offset
long countVariableAddressOffset = unsafe.objectFieldOffset(countVariableField);
System.out.println("CASDemo类中count属性内存偏移地址:" + countVariableAddressOffset);
// 我们来玩compareAndSwapInt了
boolean success = unsafe.compareAndSwapInt(instance, countVariableAddressOffset, 0, 1);
System.out.println("CAS 成功:" + success);
System.out.println("经过CAS,count值变为:" + instance.count);
}
}
另外对于x86 CPU,CAS实际是一条名为“cmpxchg”的指令,了解即可。
最后希望这个回答你能彻底明白