Java8 Unsafe 解開你神秘的面紗

前言

Unsafe 類一直是個(gè)很神秘的角色,我們普通開發(fā)者幾乎不會(huì)碰到,頂多也是使用了并發(fā)包之類的系統(tǒng)類庫(kù),間接使用到了而已。那它到底是用來(lái)做什么的呢?它提供了我們直接操作內(nèi)存的接口。Java 本身作為一個(gè)內(nèi)存自動(dòng)管理的工具,內(nèi)存的開辟釋放由虛擬機(jī)代為管理,然而,HotSpot 的設(shè)計(jì)者留下了 Unsafe 的類,用于擴(kuò)展,它可以直接開辟內(nèi)存,釋放內(nèi)存,讀取任意地址的內(nèi)存,而不受 Java 堆內(nèi)存的限制。盡管如此,它并不能為我們所用,加載這個(gè)類只能由系統(tǒng)的類加載器執(zhí)行,但我們可以通過反射獲取到它的實(shí)例對(duì)象,Java 反射的確很牛啊。

如何獲取實(shí)例對(duì)象

第一個(gè)問題:為什么我們需要通過 Field 獲取,不能使用 newInstance 獲取呢?
通過 newInstance 的方法獲取實(shí)力需要構(gòu)造函數(shù)是 public 的,否則會(huì)拋異常,及時(shí) getUnsafe 是靜態(tài)函數(shù),我們也不能通過這個(gè)去獲取,因?yàn)檫@時(shí)候類加載不是系統(tǒng)的,會(huì)拋異常

    private Unsafe() {
    }

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }
        Unsafe unsafe = Unsafe.class.newInstance();

由于 Unsafe 是單例,當(dāng)類加載時(shí),theUnsafe 實(shí)例會(huì)被加載,這樣我們就可以通過反射獲取這個(gè)實(shí)例

    static {
        registerNatives();
        Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
        // 重點(diǎn)
        theUnsafe = new Unsafe();
    }

通過 Field 獲取

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
    }

獲取到這實(shí)例,就可以干很多事情了.....
先來(lái)看看 API 圖


Screen Shot 2018-09-16 at 11.20.42 PM.png
Screen Shot 2018-09-16 at 11.20.59 PM.png
Screen Shot 2018-09-16 at 11.21.15 PM.png

太多了,眼睛都看瞎了
歸個(gè)類吧

  • 直接操作內(nèi)存,將某個(gè)對(duì)象的值更改,讀取,比如將 String 的 value 更改,是不是很神奇,這個(gè)是用反射也可以更改哦!下次面試的時(shí)候可以考考別人 String 的 value 怎么才能改的掉,看他會(huì)幾種。
        String str = "Hello Unsafe";
        Field value = str.getClass().getDeclaredField("value");
        unsafe.putObject(str, unsafe.objectFieldOffset(value), new char[]{'M', 'a', 'j', 'i', 'c'});]
        System.out.println(str);
        // output: Majic

        // throw exception
        String str = "Hello Unsafe";
        Field value = str.getClass().getDeclaredField("value");

        value.setAccessible(true);
        value.set(str, new char[] {'f', 'i', 'n', 'a', 'l'});
  • CompareAndSwap 著名的 CAS
    為了保證并發(fā)安全, CAS 涉及到的變量應(yīng)該使用 volatile 修飾,保證讀到的值最新
    allocateInstance 新建一個(gè)沒有初始化的實(shí)例,各個(gè)值都是默認(rèn)值
    compareAndSwapLong 第一個(gè)參數(shù)是 object,第二個(gè)參數(shù)是變量?jī)?nèi)存偏移值,可以用 unsafe 類獲取實(shí)際偏移值,第三個(gè)參數(shù)是 期望值,第四個(gè)三叔目標(biāo)值,大致的語(yǔ)義就是:如果內(nèi)存中是期望值,我就更新為目標(biāo)值,否則不更新
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
        InnerClass o = (InnerClass)unsafe.allocateInstance(InnerClass.class);
        o.print(); // print 100
        Field a = o.getClass().getDeclaredField("value");
        unsafe.putLong(o, unsafe.objectFieldOffset(a), 10000);
        o.print(); // print 10000
        unsafe.compareAndSwapLong(o, unsafe.objectFieldOffset(a), 10000, 1111);
        o.print(); // print 1111
        unsafe.compareAndSwapLong(o, unsafe.objectFieldOffset(a), 1000, 10000);
        o.print(); // print 1111
    }
     
    static class InnerClass {
        // 保證內(nèi)存可見性
        private volatile long value;
        InnerClass() {
            value = 100L;
        }
        void print() {
            System.err.println("value==>" + value);
        }
    }
  • 線程掛起,取消
    使用 unsafe.unpark 可以取消 Thread.sleep() 后者 park 的線程
    使用 unsafe.park(false, 1000000000) 可以掛起當(dāng)前線程,第一個(gè)參數(shù)表示是isAbsolute,是否是絕對(duì)時(shí)間,后一個(gè)參數(shù)為時(shí)間,flase 表示相對(duì)時(shí)間,0表示一直掛起,單位為納秒;true 表示絕對(duì)時(shí)間,單位為毫秒,System.currentThreadMillis 搭配使用
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException, InterruptedException {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);

        InnerThread innerThread = new InnerThread(unsafe);
        innerThread.run();

        Thread.sleep(20);
        // 取消掛起
        unsafe.unpark(innerThread);
    }

    static class InnerThread extends Thread {
        Unsafe unsafe;

        InnerThread(Unsafe unsafe) {
            this.unsafe = unsafe;
        }

        @Override
        public void run() {
            System.out.println("start");
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //unsafe.park(false, 1000000000L);
            System.out.println("end");
        }
    }

小結(jié)

以后又可以吹一波了,一箭雙雕,反射,Unsafe

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,544評(píng)論 19 139
  • 無(wú)鎖的概念 在談?wù)摕o(wú)鎖概念時(shí),總會(huì)關(guān)聯(lián)起樂觀派與悲觀派,對(duì)于樂觀派而言,他們認(rèn)為事情總會(huì)往好的方向發(fā)展,總是認(rèn)為壞...
    架構(gòu)師springboot閱讀 1,136評(píng)論 0 4
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 30,223評(píng)論 8 265
  • 豐樂河上龍舟勁舞 漁梁壩邊鐘馗出山 一個(gè)又一個(gè)熱鬧場(chǎng)景 是去歲留下的印象 艾葉插門 雄黃點(diǎn)額 五毒入不了門 同樣是...
    補(bǔ)拙莫如勤LV閱讀 346評(píng)論 0 0
  • 文藝片,總會(huì)講述一些略帶悲傷的故事,也許,也正是文中的經(jīng)典詞話與現(xiàn)實(shí)骨感的苛刻相對(duì),才造就了大部分文藝片中的魂。 ...
    還沒想好_c2dd閱讀 318評(píng)論 0 0

友情鏈接更多精彩內(nèi)容