Unsafe
Unfase为我们提供了访问底层的机制,仅供java核心类库使用。
因此普通用户程序无法直接获取其实例,且unsafe的构造方法为私有的,但是我们可以通过反射获取。
1.获取unsafe
Unsafe有一个getUnsafe()方法可以获取实例:
@CallerSensitivepublicstatic UnsafegetUnsafe(){
Classvar0= Reflection.getCallerClass();if(!VM.isSystemDomainLoader(var0.getClassLoader())){thrownewSecurityException("Unsafe");}else{return theUnsafe;}}
其返回的是thUnsafe,private static final Unsafe theUnsafe;
,因此我们可以反射获取该实例:
publicstaticvoidmain(String[] args)throws NoSuchFieldException, IllegalAccessException{
Unsafe unsafe=getUnsafe();
System.out.println(unsafe);}/**
* 获取Unsafe实例
* @return
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/publicstatic UnsafegetUnsafe()throws NoSuchFieldException,IllegalAccessException{
Field field= Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);return(Unsafe)field.get(null);}
2.unsafe创建对象
publicclassUnSafeDemo{publicstaticvoidmain(String[] args)throws NoSuchFieldException, IllegalAccessException, InstantiationException{//2.创建对象newInstance();}publicstaticvoidnewInstance()throws NoSuchFieldException, IllegalAccessException, InstantiationException{
Unsafe unsafe=getUnsafe();
Book book=(Book) unsafe.allocateInstance(Book.class);
System.out.println(book.getName()+"\t"+book.getPrice());}}classBook{private String name;private Integer price;publicBook(){
name="三国演义";
price=77;}public StringgetName(){return name;}publicvoidsetName(String name){this.name= name;}public IntegergetPrice(){return price;}publicvoidsetPrice(Integer price){this.price= price;}}
打印结果为null null,因为:
allocateInstance方法用于创建一个类的实例,但是不会调用这个实例的构造方法,如果这个类还未被初始化,则初始化这个类。
3. 直接内存操作
// 分配内存(堆外)publicnativelongallocateMemory(long var1);// 重新分配内存publicnativelongreallocateMemory(long var1,long var3);// 内存初始化publicnativevoidsetMemory(long var1,long var3,byte var5);// 内存复制publicnativevoidcopyMemory(Object var1,long var2, Object var4,long var5,long var7);// 清除内存publicnativevoidfreeMemory(long var1);
我们可以调用allocateMemory
方法为进程分配堆外的本地内存,但因为这部分内存不受JVM管辖范围,因此需要freeMemory
方法进行回收
4. CAS操作
JUC中大量运用了CAS操作,CAS操作是juc包的基础。Unsafe中提供了int,long和CAS即Compare and Swap,是一种无锁化的算法,如果非要说是一种锁的化,那就是乐观锁,只要在操作数据的时候才会进行比较更新,比悲观锁处理效率更高。
参数1:要修改的对象
参数2: 偏移量
参数3:期望值oldValue
参数4: 更新的值newValue
publicfinalnativebooleancompareAndSwapObject(Object var1,long var2, Object var4, Object var5);publicfinalnativebooleancompareAndSwapInt(Object var1,long var2,int var4,int var5);publicfinalnativebooleancompareAndSwapLong(Object var1,long var2,long var4,long var6);
5. 异常抛出
使用Unsafe的throwException不需要再方法上抛出:
unsafe.throwException(newIllegalArgumentException());
6.线程相关
publicnativevoidunpark(Object var1);publicnativevoidpark(boolean var1,long var2);publicnativevoidmonitorEnter(Object var1);publicnativevoidmonitorExit(Object var1);publicnativebooleantryMonitorEnter(Object var1);
LockSupport中使用了park和unpark:
publicstaticvoidpark(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:
- 第一个参数:修改对象
- 第二个参数:内存偏移地址
- 第三个参数:要修改的新值
publicnativeintgetInt(Object var1,long var2);publicnativevoidputInt(Object var1,long var2,int var4);
publicstaticvoidgetAndPut()throws InstantiationException, NoSuchFieldException{
Unsafe unsafe=getUnsafe();
Book book=newBook();
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,就说明该操作保证了有序性和可见性。
publicnative ObjectgetObjectVolatile(Object var1,long var2);publicnativevoidputObjectVolatile(Object var1,long var2, Object var4);
9.order相关
publicnativevoidputOrderedObject(Object var1,long var2, Object var4);publicnativevoidputOrderedInt(Object var1,long var2,int var4);publicnativevoidputOrderedLong(Object var1,long var2,long var4);
保证了有序性的写和修改。仅保证了有序性。因此不保证可见性和原子性。