sun.misc.Unsafe的各種神技

轉自:http://blog.csdn.net/dfdsggdgg/article/details/51543545

sun.misc.Unsafe包下載

http://download.csdn.net/detail/dfdsggdgg/9535347

實例化私有類

正常情況下沒法實例化一個私有構造函數的類,但是Unsafe可以做到。

import java.lang.reflect.Field;  

import sun.misc.Unsafe;  

public class UnsafePlayer {  

    public static void main(String[] args) throws Exception {    
    //通過反射實例化Unsafe  
        Field f = Unsafe.class.getDeclaredField("theUnsafe");  
        f.setAccessible(true);    
        Unsafe unsafe = (Unsafe) f.get(null);    

        //實例化Player  
        Player player = (Player) unsafe.allocateInstance(Player.class);   
        player.setName("li lei");  
        System.out.println(player.getName());  

    }    
}    

class Player{   

    private String name;  

    private Player(){}  

    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
} 

cas原子級操作&&通過內存偏移地址修改變量值

import java.lang.reflect.Field;  

import sun.misc.Unsafe;  

public class UnsafePlayer {  

    public static void main(String[] args) throws Exception {    
        //通過反射實例化Unsafe  
        Field f = Unsafe.class.getDeclaredField("theUnsafe");  
        f.setAccessible(true);    
        Unsafe unsafe = (Unsafe) f.get(null);    

        //實例化Player  
        Player player = (Player) unsafe.allocateInstance(Player.class);   
        player.setAge(18);  
        player.setName("li lei");  
        for(Field field:Player.class.getDeclaredFields()){  
            System.out.println(field.getName()+":對應的內存偏移地址"+unsafe.objectFieldOffset(field));  
        }  
        System.out.println("-------------------");  

        int ageOffset= 8;  
        //修改內存偏移地址爲8的值(age),返回true,說明通過內存偏移地址修改age的值成功  
        System.out.println(unsafe.compareAndSwapInt(player, ageOffset, 18, 20));  
        System.out.println("age修改後的值:"+player.getAge());  
        System.out.println("-------------------");  

        //修改內存偏移地址爲8的值,但是修改後不保證立馬能被其他的線程看到。  
        unsafe.putOrderedInt(player, 8, 33);  
        System.out.println("age修改後的值:"+player.getAge());  
        System.out.println("-------------------");  

        //修改內存偏移地址爲12的值,volatile修飾,修改能立馬對其他線程可見  
        unsafe.putObjectVolatile(player, 12, "han mei");  
        System.out.println("name修改後的值:"+unsafe.getObjectVolatile(player, 12));  
    }    
}    

class Player{   

    private int age;  

    private String name;  

    private Player(){}  

    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  

    public int getAge() {  
        return age;  
    }  

    public void setAge(int age) {  
        this.age = age;  
    }  

} 

創建超級數組

java中數組的最大長度爲Integer.MAX_VALUE,正常情況下如果想創建一個大於Integer.MAX_VALUE的數組是做不到的,但是Unsafe可以,通過對內存進行直接分配實現。

import java.lang.reflect.Field;  

import sun.misc.Unsafe;  

public class SuperArray {  

    public static void main(String[] arg) throws Exception{  

        //通過反射實例化Unsafe  
        Field f = Unsafe.class.getDeclaredField("theUnsafe");  
        f.setAccessible(true);    
         Unsafe unsafe = (Unsafe) f.get(null);    

         //只要內存夠大,可以把這個調大,大於Integer.MAX_VALUE  
         long size = (long)Integer.MAX_VALUE/2 ;    
         long addr = unsafe.allocateMemory(size);  
         System.out.println("unsafe address :"+addr);  

         for (int i = 0; i < size; i++) {    
             unsafe.putByte(addr+i, (byte)6);   
             if(unsafe.getByte(addr+i) !=6){  
                 System.out.println("failed at offset");  
             }   
        }    
    }  

}

把size調大,size = (long)Integer.MAX_VALUE*2,錯誤信息如下。

unsafe address :15817328  
#  
# A fatal error has been detected by the Java Runtime Environment:  
#  
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x61cc0350, pid=31240, tid=31324  
#  
# JRE version: Java(TM) SE Runtime Environment (8.0_45-b14) (build 1.8.0_45-b14)  
# Java VM: Java HotSpot(TM) Client VM (25.45-b02 mixed mode windows-x86 )  
# Problematic frame:  
# V[thread 30484 also had an error]  
  [jvm.dll+0x40350]  
#  
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows  
#  
# An error report file with more information is saved as:  
# C:\welab\workspace\Person\hs_err_pid31240.log 

線程掛起與恢復

將一個線程進行掛起是通過park方法實現的,調用 park後,線程將一直阻塞直到超時或者中斷等條件出現。unpark可以終止一個掛起的線程,使其恢復正常。整個併發框架中對線程的掛起操作被封裝在 LockSupport類中,LockSupport類中有各種版本pack方法,但最終都調用了Unsafe.park()方法。

public class LockSupport {    

    /** 
     * 恢復阻塞線程 
     */  
    public static void unpark(Thread thread) {    
        if (thread != null)    
            unsafe.unpark(thread);    
    }    

    /** 
     * 一直阻塞當前線程,調用Unsafe.park()方法 
     */  
    public static void park(Object blocker) {    
        Thread t = Thread.currentThread();    
        setBlocker(t, blocker);    
        unsafe.park(false, 0L);    
        setBlocker(t, null);    
    }    
    /** 
     * 阻塞當前線程nanos納秒 
     */  
    public static void parkNanos(Object blocker, long nanos) {    
        if (nanos > 0) {    
            Thread t = Thread.currentThread();    
            setBlocker(t, blocker);    
            unsafe.park(false, nanos);    
            setBlocker(t, null);    
        }    
    }    

    public static void parkUntil(Object blocker, long deadline) {    
        Thread t = Thread.currentThread();    
        setBlocker(t, blocker);    
        unsafe.park(true, deadline);    
        setBlocker(t, null);    
    }    

    /** 
     * 一直阻塞當前線程 
     */  
    public static void park() {    
        unsafe.park(false, 0L);    
    }    

   /** 
     * 阻塞當前線程nanos納秒 
     */  
    public static void parkNanos(long nanos) {    
        if (nanos > 0)    
            unsafe.park(false, nanos);    
    }    

    public static void parkUntil(long deadline) {    
        unsafe.park(true, deadline);    
    }    
}  

最後看下阻塞和恢復的例子

import java.util.concurrent.locks.LockSupport;  

public class Lock {  

    public static void main(String[] args) throws InterruptedException {  

        ThreadPark threadPark = new ThreadPark();  
        threadPark.start();  
        ThreadUnPark threadUnPark = new ThreadUnPark(threadPark);  
        threadUnPark.start();  
        //等待threadUnPark執行成功  
        threadUnPark.join();  
        System.out.println("運行成功....");  
    }  


  static  class ThreadPark extends Thread{  

       public void run(){  
            System.out.println(Thread.currentThread() +"我將被阻塞在這了60s....");  
            //阻塞60s,單位納秒  1s = 1000000000  
            LockSupport.parkNanos(1000000000l*60);  

            System.out.println(Thread.currentThread() +"我被恢復正常了....");  
       }  
   }  

  static  class ThreadUnPark extends Thread{  

       public Thread thread = null;  

       public ThreadUnPark(Thread thread){  
           this.thread = thread;  
       }  
       public void run(){  

            System.out.println("提前恢復阻塞線程ThreadPark");  
            //恢復阻塞線程  
            LockSupport.unpark(thread);  

       }  
   }  
}  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章