Java中的Unsafe

http://www.reibang.com/p/db8dce09232d
[toc]

Java和C++語(yǔ)言的一個(gè)重要區(qū)別就是Java中我們無(wú)法直接操作一塊內(nèi)存區(qū)域鸽照,不能像C++中那樣可以自己申請(qǐng)內(nèi)存和釋放內(nèi)存汽纤。Java中的Unsafe類為我們提供了類似C++手動(dòng)管理內(nèi)存的能力。
Unsafe類,全限定名是sun.misc.Unsafe园骆,從名字中我們可以看出來(lái)這個(gè)類對(duì)普通程序員來(lái)說(shuō)是“危險(xiǎn)”的,一般應(yīng)用開(kāi)發(fā)者不會(huì)用到這個(gè)類胜卤。

Unsafe類是"final"的祖能,不允許繼承。且構(gòu)造函數(shù)是private的:

public final class Unsafe {
    private static final Unsafe theUnsafe;
    public static final int INVALID_FIELD_OFFSET = -1;

    private static native void registerNatives();
    // 構(gòu)造函數(shù)是private的籽暇,不允許外部實(shí)例化
    private Unsafe() {
    }
    ...
}

因此我們無(wú)法在外部對(duì)Unsafe進(jìn)行實(shí)例化温治。

獲取Unsafe

Unsafe無(wú)法實(shí)例化,那么怎么獲取Unsafe呢戒悠?答案就是通過(guò)反射來(lái)獲取Unsafe:

public Unsafe getUnsafe() throws IllegalAccessException {
    Field unsafeField = Unsafe.class.getDeclaredFields()[0];
    unsafeField.setAccessible(true);
    Unsafe unsafe = (Unsafe) unsafeField.get(null);
    return unsafe;
}

主要功能

Unsafe的功能如下圖:

Unsafe-xmind

普通讀寫

通過(guò)Unsafe可以讀寫一個(gè)類的屬性熬荆,即使這個(gè)屬性是私有的,也可以對(duì)這個(gè)屬性進(jìn)行讀寫绸狐。

讀寫一個(gè)Object屬性的相關(guān)方法

public native int getInt(Object var1, long var2);

public native void putInt(Object var1, long var2, int var4);
getInt用于從對(duì)象的指定偏移地址處讀取一個(gè)int卤恳。putInt用于在對(duì)象指定偏移地址處寫入一個(gè)int。其他的primitive type也有對(duì)應(yīng)的方法寒矿。

Unsafe還可以直接在一個(gè)地址上讀寫

public native byte getByte(long var1);

public native void putByte(long var1, byte var3);

getByte用于從指定內(nèi)存地址處開(kāi)始讀取一個(gè)byte突琳。putByte用于從指定內(nèi)存地址寫入一個(gè)byte。其他的primitive type也有對(duì)應(yīng)的方法符相。

volatile讀寫

普通的讀寫無(wú)法保證可見(jiàn)性和有序性本今,而volatile讀寫就可以保證可見(jiàn)性和有序性。

public native int getIntVolatile(Object var1, long var2);

public native void putIntVolatile(Object var1, long var2, int var4);

getIntVolatile方法用于在對(duì)象指定偏移地址處volatile讀取一個(gè)int主巍。putIntVolatile方法用于在對(duì)象指定偏移地址處volatile寫入一個(gè)int。

volatile讀寫相對(duì)普通讀寫是更加昂貴的挪凑,因?yàn)樾枰WC可見(jiàn)性和有序性孕索,而與volatile寫入相比putOrderedXX寫入代價(jià)相對(duì)較低,putOrderedXX寫入不保證可見(jiàn)性躏碳,但是保證有序性搞旭,所謂有序性,就是保證指令不會(huì)重排序菇绵。

有序?qū)懭?/h2>

有序?qū)懭胫槐WC寫入的有序性肄渗,不保證可見(jiàn)性,就是說(shuō)一個(gè)線程的寫入不保證其他線程立馬可見(jiàn)咬最。

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);

直接內(nèi)存操作

我們都知道Java不可以直接對(duì)內(nèi)存進(jìn)行操作翎嫡,對(duì)象內(nèi)存的分配和回收都是由JVM幫助我們實(shí)現(xiàn)的。但是Unsafe為我們?cè)贘ava中提供了直接操作內(nèi)存的能力永乌。

// 分配內(nèi)存
public native long allocateMemory(long var1);
// 重新分配內(nèi)存
public native long reallocateMemory(long var1, long var3);
// 內(nèi)存初始化
public native void setMemory(long var1, long var3, byte var5);
// 內(nèi)存復(fù)制
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
// 清除內(nèi)存
public native void freeMemory(long var1);

CAS相關(guān)

JUC中大量運(yùn)用了CAS操作惑申,可以說(shuō)CAS操作是JUC的基礎(chǔ)具伍,因此CAS操作是非常重要的。Unsafe中提供了int,long和Object的CAS操作:

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);

CAS一般用于樂(lè)觀鎖圈驼,它在Java中有廣泛的應(yīng)用人芽,ConcurrentHashMap,ConcurrentLinkedQueue中都有用到CAS來(lái)實(shí)現(xiàn)樂(lè)觀鎖绩脆。

偏移量相關(guān)

public native long staticFieldOffset(Field var1);

public native long objectFieldOffset(Field var1);

public native Object staticFieldBase(Field var1);

public native int arrayBaseOffset(Class<?> var1);

public native int arrayIndexScale(Class<?> var1);

staticFieldOffset方法用于獲取靜態(tài)屬性Field在對(duì)象中的偏移量萤厅,讀寫靜態(tài)屬性時(shí)必須獲取其偏移量。objectFieldOffset方法用于獲取非靜態(tài)屬性Field在對(duì)象實(shí)例中的偏移量靴迫,讀寫對(duì)象的非靜態(tài)屬性時(shí)會(huì)用到這個(gè)偏移量惕味。staticFieldBase方法用于返回Field所在的對(duì)象。arrayBaseOffset方法用于返回?cái)?shù)組中第一個(gè)元素實(shí)際地址相對(duì)整個(gè)數(shù)組對(duì)象的地址的偏移量矢劲。arrayIndexScale方法用于計(jì)算數(shù)組中第一個(gè)元素所占用的內(nèi)存空間赦拘。

線程調(diào)度

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);

park方法和unpark方法相信看過(guò)LockSupport類的都不會(huì)陌生,這兩個(gè)方法主要用來(lái)掛起和喚醒線程芬沉。LockSupport中的park和unpark方法正是通過(guò)Unsafe來(lái)實(shí)現(xiàn)的:

// 掛起線程
public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker); // 通過(guò)Unsafe的putObject方法設(shè)置阻塞阻塞當(dāng)前線程的blocker
    UNSAFE.park(false, 0L); // 通過(guò)Unsafe的park方法來(lái)阻塞當(dāng)前線程躺同,注意此方法將當(dāng)前線程阻塞后,當(dāng)前線程就不會(huì)繼續(xù)往下走了丸逸,直到其他線程unpark此線程
    setBlocker(t, null); // 清除blocker
}

// 喚醒線程
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

monitorEnter方法和monitorExit方法用于加鎖蹋艺,Java中的synchronized鎖就是通過(guò)這兩個(gè)指令來(lái)實(shí)現(xiàn)的。

類加載

public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);

public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);

public native Object allocateInstance(Class<?> var1) throws InstantiationException;

public native boolean shouldBeInitialized(Class<?> var1);

public native void ensureClassInitialized(Class<?> var1);

defineClass方法定義一個(gè)類黄刚,用于動(dòng)態(tài)地創(chuàng)建類捎谨。
defineAnonymousClass用于動(dòng)態(tài)的創(chuàng)建一個(gè)匿名內(nèi)部類。
allocateInstance方法用于創(chuàng)建一個(gè)類的實(shí)例憔维,但是不會(huì)調(diào)用這個(gè)實(shí)例的構(gòu)造方法涛救,如果這個(gè)類還未被初始化,則初始化這個(gè)類业扒。
shouldBeInitialized方法用于判斷是否需要初始化一個(gè)類检吆。
ensureClassInitialized方法用于保證已經(jīng)初始化過(guò)一個(gè)類。

內(nèi)存屏障

public native void loadFence();

public native void storeFence();

public native void fullFence();

loadFence:保證在這個(gè)屏障之前的所有讀操作都已經(jīng)完成程储。
storeFence:保證在這個(gè)屏障之前的所有寫操作都已經(jīng)完成蹭沛。
fullFence:保證在這個(gè)屏障之前的所有讀寫操作都已經(jīng)完成。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末章鲤,一起剝皮案震驚了整個(gè)濱河市摊灭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌败徊,老刑警劉巖帚呼,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異集嵌,居然都是意外死亡萝挤,警方通過(guò)查閱死者的電腦和手機(jī)御毅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怜珍,“玉大人端蛆,你說(shuō)我怎么就攤上這事∷址海” “怎么了今豆?”我有些...
    開(kāi)封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)柔袁。 經(jīng)常有香客問(wèn)我呆躲,道長(zhǎng),這世上最難降的妖魔是什么捶索? 我笑而不...
    開(kāi)封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任插掂,我火速辦了婚禮,結(jié)果婚禮上腥例,老公的妹妹穿的比我還像新娘辅甥。我一直安慰自己,他們只是感情好燎竖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布璃弄。 她就那樣靜靜地躺著,像睡著了一般构回。 火紅的嫁衣襯著肌膚如雪夏块。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天纤掸,我揣著相機(jī)與錄音脐供,去河邊找鬼。 笑死借跪,一個(gè)胖子當(dāng)著我的面吹牛患民,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播垦梆,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼仅孩!你這毒婦竟也來(lái)了托猩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辽慕,失蹤者是張志新(化名)和其女友劉穎京腥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體溅蛉,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡公浪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年他宛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欠气。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厅各,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出预柒,到底是詐尸還是另有隱情队塘,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布宜鸯,位于F島的核電站憔古,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏淋袖。R本人自食惡果不足惜鸿市,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望即碗。 院中可真熱鬧焰情,春花似錦、人聲如沸拜姿。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蕊肥。三九已至谒获,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間壁却,已是汗流浹背批狱。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留展东,地道東北人赔硫。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像盐肃,于是被迫代替她去往敵國(guó)和親爪膊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Java和C++語(yǔ)言的一個(gè)重要區(qū)別就是Java中我們無(wú)法直接操作一塊內(nèi)存區(qū)域砸王,不能像C++中那樣可以自己申請(qǐng)內(nèi)存和...
    zhong0316閱讀 44,846評(píng)論 3 47
  • java不能直接訪問(wèn)操作系統(tǒng)底層推盛,而是通過(guò)本地方法來(lái)訪問(wèn)。Unsafe類提供了硬件級(jí)別的原子操作谦铃。Java和C++...
    笨比喬治閱讀 211評(píng)論 0 1
  • 基本介紹 Unsafe是位于sun.misc包下的一個(gè)類耘成,主要提供一些用于執(zhí)行低級(jí)別、不安全操作的方法,如直接訪問(wèn)...
    曾澤浩閱讀 327評(píng)論 0 1
  • 簡(jiǎn)介 Java是一種安全的編程語(yǔ)言瘪菌,可以防止程序員犯許多愚蠢的錯(cuò)誤撒会,其中大多數(shù)錯(cuò)誤都是基于內(nèi)存管理的。但是师妙,有一種...
    多喝水JS閱讀 1,206評(píng)論 0 1
  • Unsafe 就像這個(gè)類名一樣诵肛,這個(gè)類本身就不是很安全,Unsafe類使Java擁有了像C語(yǔ)言的指針一樣操作內(nèi)存空...
    DeanChangDM閱讀 697評(píng)論 0 2