Unsafe
Unfase为我们提供了访问底层的机制,仅供java核心类库使用。
因此普通用户程序无法直接获取其实例,且unsafe的构造方法为私有的,但是我们可以通过反射获取。
1.获取unsafe
Unsafe有一个getUnsafe()方法可以获取实例:
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
其返回的是thUnsafe,private static final Unsafe theUnsafe;
,因此我们可以反射获取该实例:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Unsafe unsafe = getUnsafe();
System.out.println(unsafe);
}
/**
* 获取Unsafe实例
* @return
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public static Unsafe getUnsafe() throws NoSuchFieldException,IllegalAccessException {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe)field.get(null);
}
2.unsafe创建对象
public class UnSafeDemo {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
//2.创建对象
newInstance();
}
public static void newInstance() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
Unsafe unsafe = getUnsafe();
Book book = (Book) unsafe.allocateInstance(Book.class);
System.out.println(book.getName()+"\t"+book.getPrice());
}
}
class Book {
private String name;
private Integer price;
public Book() {
name="三国演义";
price=77;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
打印结果为null null,因为:
allocateInstance方法用于创建一个类的实例,但是不会调用这个实例的构造方法,如果这个类还未被初始化,则初始化这个类。
3. 直接内存操作
// 分配内存(堆外)
public native long allocateMemory(long var1);
// 重新分配内存
public native long reallocateMemory(long var1, long var3);
// 内存初始化
public native void setMemory(long var1, long var3, byte var5);
// 内存复制
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
// 清除内存
public native void freeMemory(long var1);
我们可以调用allocateMemory
方法为进程分配堆外的本地内存,但因为这部分内存不受JVM管辖范围,因此需要freeMemory
方法进行回收
4. CAS操作
JUC中大量运用了CAS操作,CAS操作是juc包的基础。Unsafe中提供了int,long和CAS即Compare and Swap,是一种无锁化的算法,如果非要说是一种锁的化,那就是乐观锁,只要在操作数据的时候才会进行比较更新,比悲观锁处理效率更高。
参数1:要修改的对象
参数2: 偏移量
参数3:期望值oldValue
参数4: 更新的值newValue
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
5. 异常抛出
使用Unsafe的throwException不需要再方法上抛出:
unsafe.throwException(new IllegalArgumentException());
6.线程相关
public native void unpark(Object var1);
public native void park(boolean var1, long var2);
public native void monitorEnter(Object var1);
public native void monitorExit(Object var1);
public native boolean tryMonitorEnter(Object var1);
LockSupport中使用了park和unpark:
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
线程需要阻塞时,调用park()方法,线程需要继续运行时,调用unpark()方法
monitorEnter:
锁定对象,必须通过monitorExit
方法才能解锁。可重入的。
加了 synchronized
关键字的代码段,生成的字节码文件会多出 monitorenter
和 monitorexit
两条指令
7. putXXX 和getXXX
以int为例:
-
getInt:
- 第一个参数:读取对象
- 第二个参数:内存偏移地址
-
putInt:
- 第一个参数:修改对象
- 第二个参数:内存偏移地址
- 第三个参数:要修改的新值
public native int getInt(Object var1, long var2);
public native void putInt(Object var1, long var2, int var4);
public static void getAndPut() throws InstantiationException, NoSuchFieldException {
Unsafe unsafe = getUnsafe();
Book book =new Book();
Field field = book.getClass().getDeclaredField("name");
unsafe.putObject(book,unsafe.objectFieldOffset(field),"新三国演义");
System.out.println(book.getName());//新三国演义
}
unsafe.objectFieldOffset(field): 获取对应字段的内存偏移地址
8. volatile相关
getXXXVolatile:以volatile的形式读取内存偏移地址为var2的对象的值。
putXXXVolatile:以volatile的形式修改内存偏移地址为var2的对象的值
既然使用了volatile,就说明该操作保证了有序性和可见性。
public native Object getObjectVolatile(Object var1, long var2);
public native void putObjectVolatile(Object var1, long var2, Object var4);
9.order相关
public native void putOrderedObject(Object var1, long var2, Object var4);
public native void putOrderedInt(Object var1, long var2, int var4);
public native void putOrderedLong(Object var1, long var2, long var4);
保证了有序性的写和修改。仅保证了有序性。因此不保证可见性和原子性。