Java Unsafe類

1.Unsafe類簡介

  • Unsafe類是在sun.misc包下,不屬于Java標(biāo)準(zhǔn)底哗。但是很多Java的基礎(chǔ)類庫默伍,包括一些被廣泛使用的高性能開發(fā)庫都是基于Unsafe類開發(fā)的邮利,比如Netty芹缔、Cassandra、Hadoop、Kafka等。Unsafe類在提升Java運(yùn)行效率宁炫,增強(qiáng)Java語言底層操作能力方面起了很大的作用。

  • Unsafe類使Java擁有了像C語言的指針一樣操作內(nèi)存空間的能力击吱,同時也帶來了指針的問題淋淀。過度的使用Unsafe類會使得出錯的幾率變大遥昧,因此Java官方并不建議使用的覆醇,官方文檔也幾乎沒有。

  • Unsafe類包路徑變化
    1.8之前Unsafe的包路徑為:

package sun.misc;

而到了java9炭臭,它的包路徑改成了下面這個永脓,說明這個類已經(jīng)開放使用。

package jdk.internal.misc;
  • 獲取Unsafe實(shí)例方式
    1.8之前Unsafe是不公開的類鞋仍,只能通過反射或者使用系統(tǒng)類加載器使用常摧,利用反射的使用方式如下。這里不再詳細(xì)分析威创。
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);

而到了java9落午,Unsafe包含了一個靜態(tài)方法,可以直接拿到theUnsafe對象肚豺。如下溃斋。

/**
 * 給調(diào)用者提供執(zhí)行不安全操作的能力
 */
public static Unsafe getUnsafe() {
    return theUnsafe;
}

2.Unsafe類功能分類

2.1 內(nèi)存管理。包括分配內(nèi)存吸申、釋放內(nèi)存等梗劫。

該部分包括了allocateMemory(分配內(nèi)存)、reallocateMemory(重新分配內(nèi)存)截碴、copyMemory(拷貝內(nèi)存)梳侨、freeMemory(釋放內(nèi)存 )、getAddress(獲取內(nèi)存地址)日丹、addressSize走哺、pageSize、getInt(獲取內(nèi)存地址指向的整數(shù))哲虾、getIntVolatile(獲取內(nèi)存地址指向的整數(shù)割坠,并支持volatile語義)、putInt(將整數(shù)寫入指定內(nèi)存地址)妒牙、putIntVolatile(將整數(shù)寫入指定內(nèi)存地址彼哼,并支持volatile語義)、putOrderedInt(將整數(shù)寫入指定內(nèi)存地址湘今、有序或者有延遲的方法)等方法敢朱。getXXX和putXXX包含了各種基本類型的操作。

利用copyMemory方法,我們可以實(shí)現(xiàn)一個通用的對象拷貝方法拴签,無需再對每一個對象都實(shí)現(xiàn)clone方法孝常,當(dāng)然這通用的方法只能做到對象淺拷貝。

2.2 非常規(guī)的對象實(shí)例化蚓哩。

allocateInstance()方法提供了另一種創(chuàng)建實(shí)例的途徑构灸。通常我們可以用new或者反射來實(shí)例化對象,使用allocateInstance()方法可以直接生成對象實(shí)例岸梨,且無需調(diào)用構(gòu)造方法和其它初始化方法喜颁。

這在對象反序列化的時候會很有用,能夠重建和設(shè)置final字段曹阔,而不需要調(diào)用構(gòu)造方法半开。

2.3 操作類、對象赃份、變量寂拆。

這部分包括了staticFieldOffset(靜態(tài)域偏移)、defineClass(定義類)抓韩、defineAnonymousClass(定義匿名類)纠永、ensureClassInitialized(確保類初始化)、objectFieldOffset(對象域偏移)等方法谒拴。

通過這些方法我們可以獲取對象的指針尝江,通過對指針進(jìn)行偏移,我們不僅可以直接修改指針指向的數(shù)據(jù)(即使它們是私有的)彪薛,甚至可以找到JVM已經(jīng)認(rèn)定為垃圾茂装、可以進(jìn)行回收的對象。

2.4 數(shù)組操作善延。

這部分包括了arrayBaseOffset(獲取數(shù)組第一個元素的偏移地址)少态、arrayIndexScale(獲取數(shù)組中元素的增量地址)等方法。arrayBaseOffset與arrayIndexScale配合起來使用易遣,就可以定位數(shù)組中每個元素在內(nèi)存中的位置彼妻。

由于Java的數(shù)組最大值為Integer.MAX_VALUE,使用Unsafe類的內(nèi)存分配方法可以實(shí)現(xiàn)超大數(shù)組豆茫。實(shí)際上這樣的數(shù)據(jù)就可以認(rèn)為是C數(shù)組侨歉,因此需要注意在合適的時間釋放內(nèi)存。

2.5 多線程同步揩魂。包括鎖機(jī)制幽邓、CAS操作等。

這部分包括了monitorEnter火脉、tryMonitorEnter牵舵、monitorExit柒啤、compareAndSwapInt、compareAndSwap等方法畸颅。

其中monitorEnter担巩、tryMonitorEnter、monitorExit已經(jīng)被標(biāo)記為deprecated没炒,不建議使用涛癌。

Unsafe類的CAS操作可能是用的最多的,它為Java的鎖機(jī)制提供了一種新的解決辦法送火,比如AtomicInteger等類都是通過該方法來實(shí)現(xiàn)的拳话。compareAndSwap方法是原子的,可以避免繁重的鎖機(jī)制漾脂,提高代碼效率假颇。這是一種樂觀鎖胚鸯,通常認(rèn)為在大部分情況下不出現(xiàn)競態(tài)條件骨稿,如果操作失敗,會不斷重試直到成功姜钳。

2.6 掛起與恢復(fù)坦冠。

這部分包括了park、unpark等方法哥桥。

將一個線程進(jìn)行掛起是通過park方法實(shí)現(xiàn)的辙浑,調(diào)用 park后,線程將一直阻塞直到超時或者中斷等條件出現(xiàn)拟糕。unpark可以終止一個掛起的線程判呕,使其恢復(fù)正常。整個并發(fā)框架中對線程的掛起操作被封裝在 LockSupport類中送滞,LockSupport類中有各種版本pack方法侠草,但最終都調(diào)用了Unsafe.park()方法。

2.7 內(nèi)存屏障犁嗅。

這部分包括了loadFence边涕、storeFence、fullFence等方法褂微。這是在Java 8新引入的功蜓,用于定義內(nèi)存屏障,避免代碼重排序宠蚂。

loadFence() 表示該方法之前的所有l(wèi)oad操作在內(nèi)存屏障之前完成式撼。同理storeFence()表示該方法之前的所有store操作在內(nèi)存屏障之前完成。fullFence()表示該方法之前的所有l(wèi)oad求厕、store操作在內(nèi)存屏障之前完成著隆。

3.ConcurrentHashMap中使用Unsafe

 // Unsafe mechanics
    private static final Unsafe U = Unsafe.getUnsafe();
    private static final long SIZECTL;
    private static final long TRANSFERINDEX;
    private static final long BASECOUNT;
    private static final long CELLSBUSY;
    private static final long CELLVALUE;
    private static final int ABASE;
    private static final int ASHIFT;

    static {
  • 獲取ConcurrentHashMap類的域變量sizeCtl transferIndex等
        SIZECTL = U.objectFieldOffset
            (ConcurrentHashMap.class, "sizeCtl");
        TRANSFERINDEX = U.objectFieldOffset
            (ConcurrentHashMap.class, "transferIndex");
        BASECOUNT = U.objectFieldOffset
            (ConcurrentHashMap.class, "baseCount");
        CELLSBUSY = U.objectFieldOffset
            (ConcurrentHashMap.class, "cellsBusy");

        CELLVALUE = U.objectFieldOffset
            (CounterCell.class, "value");
  • 獲取ConcurrentHashMap類Node[]數(shù)組第一個元素的偏移地址ABASE叠洗,獲取數(shù)組中元素的增量地址scale
        ABASE = U.arrayBaseOffset(Node[].class);
        int scale = U.arrayIndexScale(Node[].class);
        if ((scale & (scale - 1)) != 0)
            throw new Error("array index scale not a power of two");
        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);

        // Reduce the risk of rare disastrous classloading in first call to
        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
        Class<?> ensureLoaded = LockSupport.class;
    }

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市旅东,隨后出現(xiàn)的幾起案子灭抑,更是在濱河造成了極大的恐慌,老刑警劉巖抵代,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腾节,死亡現(xiàn)場離奇詭異,居然都是意外死亡荤牍,警方通過查閱死者的電腦和手機(jī)案腺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來康吵,“玉大人劈榨,你說我怎么就攤上這事』耷叮” “怎么了同辣?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長惭载。 經(jīng)常有香客問我旱函,道長,這世上最難降的妖魔是什么描滔? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任棒妨,我火速辦了婚禮,結(jié)果婚禮上含长,老公的妹妹穿的比我還像新娘券腔。我一直安慰自己,他們只是感情好拘泞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布纷纫。 她就那樣靜靜地躺著,像睡著了一般田弥。 火紅的嫁衣襯著肌膚如雪涛酗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天偷厦,我揣著相機(jī)與錄音商叹,去河邊找鬼。 笑死只泼,一個胖子當(dāng)著我的面吹牛剖笙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播请唱,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼弥咪,長吁一口氣:“原來是場噩夢啊……” “哼过蹂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起聚至,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤酷勺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扳躬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脆诉,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年贷币,在試婚紗的時候發(fā)現(xiàn)自己被綠了击胜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡役纹,死狀恐怖偶摔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情促脉,我是刑警寧澤辰斋,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布,位于F島的核電站嘲叔,受9級特大地震影響亡呵,放射性物質(zhì)發(fā)生泄漏抽活。R本人自食惡果不足惜硫戈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望下硕。 院中可真熱鬧丁逝,春花似錦、人聲如沸梭姓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽誉尖。三九已至罪既,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铡恕,已是汗流浹背琢感。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留探熔,地道東北人驹针。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像诀艰,于是被迫代替她去往敵國和親柬甥。 傳聞我的和親對象是個殘疾皇子饮六,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評論 2 349