亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

簡(jiǎn)單談一談Java中的Unsafe類

 更新時(shí)間:2018年05月24日 08:34:38   作者:pkufork  
其實(shí)Java官方不推薦使用Unsafe類,因?yàn)楣俜秸J(rèn)為,這個(gè)類別人很難正確使用,非正確使用會(huì)給JVM帶來(lái)致命錯(cuò)誤。但還是要會(huì)使用,下面這篇文章就來(lái)給大家簡(jiǎn)單的談一談關(guān)于Java中Unsafe類的相關(guān)資料,需要的朋友可以參考下

Unsafe類是啥?

Java最初被設(shè)計(jì)為一種安全的受控環(huán)境。盡管如此,Java HotSpot還是包含了一個(gè)“后門”,提供了一些可以直接操控內(nèi)存和線程的低層次操作。這個(gè)后門類——sun.misc.Unsafe——被JDK廣泛用于自己的包中,如java.nio和java.util.concurrent。但是絲毫不建議在生產(chǎn)環(huán)境中使用這個(gè)后門。因?yàn)檫@個(gè)API十分不安全、不輕便、而且不穩(wěn)定。這個(gè)不安全的類提供了一個(gè)觀察HotSpot JVM內(nèi)部結(jié)構(gòu)并且可以對(duì)其進(jìn)行修改。有時(shí)它可以被用來(lái)在不適用C++調(diào)試的情況下學(xué)習(xí)虛擬機(jī)內(nèi)部結(jié)構(gòu),有時(shí)也可以被拿來(lái)做性能監(jiān)控和開(kāi)發(fā)工具。

引言

最近在看Java并發(fā)包的源碼,發(fā)現(xiàn)了神奇的Unsafe類,仔細(xì)研究了一下,在這里跟大家分享一下。

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

Unsafe類使Java擁有了像C語(yǔ)言的指針一樣操作內(nèi)存空間的能力,同時(shí)也帶來(lái)了指針的問(wèn)題。過(guò)度的使用Unsafe類會(huì)使得出錯(cuò)的幾率變大,因此Java官方并不建議使用的,官方文檔也幾乎沒(méi)有。Oracle正在計(jì)劃從Java 9中去掉Unsafe類,如果真是如此影響就太大了。

通常我們最好也不要使用Unsafe類,除非有明確的目的,并且也要對(duì)它有深入的了解才行。要想使用Unsafe類需要用一些比較tricky的辦法。Unsafe類使用了單例模式,需要通過(guò)一個(gè)靜態(tài)方法getUnsafe()來(lái)獲取。但Unsafe類做了限制,如果是普通的調(diào)用的話,它會(huì)拋出一個(gè)SecurityException異常;只有由主類加載器加載的類才能調(diào)用這個(gè)方法。其源碼如下:

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

網(wǎng)上也有一些辦法來(lái)用主類加載器加載用戶代碼,比如設(shè)置bootclasspath參數(shù)。但更簡(jiǎn)單方法是利用Java反射,方法如下:

 Field f = Unsafe.class.getDeclaredField("theUnsafe");
 f.setAccessible(true);
 Unsafe unsafe = (Unsafe) f.get(null);

獲取到Unsafe實(shí)例之后,我們就可以為所欲為了。Unsafe類提供了以下這些功能:

一、內(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語(yǔ)義)、putInt(將整數(shù)寫入指定內(nèi)存地址)、putIntVolatile(將整數(shù)寫入指定內(nèi)存地址,并支持volatile語(yǔ)義)、putOrderedInt(將整數(shù)寫入指定內(nèi)存地址、有序或者有延遲的方法)等方法。getXXX和putXXX包含了各種基本類型的操作。

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

二、非常規(guī)的對(duì)象實(shí)例化。

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

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

三、操作類、對(duì)象、變量。

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

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

四、數(shù)組操作。

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

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

五、多線程同步。包括鎖機(jī)制、CAS操作等。

這部分包括了monitorEnter、tryMonitorEnter、monitorExit、compareAndSwapInt、compareAndSwap等方法。

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

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

六、掛起與恢復(fù)。

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

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

七、內(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)存屏障之前完成。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

最新評(píng)論