成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

各大框架都在使用的Unsafe類,到底有多神奇?

開發(fā) 架構(gòu)
經(jīng)過本文的分析,想必大家在閱讀源碼時,再遇到Unsafe類的調(diào)用,一定大概猜出它是用來干什么的。使用Unsafe類的主要目的大多數(shù)情況下是為了提升運行效率、增強功能。

前言

幾乎每個使用 Java開發(fā)的工具、軟件基礎(chǔ)設(shè)施、高性能開發(fā)庫都在底層使用了sun.misc.Unsafe,比如Netty、Cassandra、Hadoop、Kafka等。

Unsafe類在提升Java運行效率,增強Java語言底層操作能力方面起了很大的作用。但Unsafe類在sun.misc包下,不屬于Java標準。

很早之前,在閱讀并發(fā)編程相關(guān)類的源碼時,看到Unsafe類,產(chǎn)生了一個疑惑:既然是并發(fā)編程中用到的類,為什么命名為Unsafe呢?

深入了解之后才知道,這里的Unsafe并不是說線程安全與否,而是指:該類對于普通的程序員來說是”危險“的,一般應(yīng)用開發(fā)者不會也不應(yīng)該用到此類。

因為Unsafe類功能過于強大,提供了一些可以繞開JVM的更底層功能。它讓Java擁有了像C語言的指針一樣操作內(nèi)存空間的能力,能夠提升效率,但也帶來了指針的問題。官方并不建議使用,也沒提供文檔支持,甚至計劃在高版本中去掉該類。

但對于開發(fā)者來說,了解該類提供的功能更有助于我們學習CAS、并發(fā)編程等相關(guān)的知識,還是非常有必要學習和了解的。

Unsafe的構(gòu)造

Unsafe類是"final"的,不允許繼承,且構(gòu)造函數(shù)是private,使用了單例模式來通過一個靜態(tài)方法getUnsafe()來獲取。

   private Unsafe() {
}

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

在getUnsafe方法中對單例模式中的對象創(chuàng)建做了限制,如果是普通的調(diào)用會拋出一個SecurityException異常。只有由主類加載器加載的類才能調(diào)用這個方法。

那么,如何獲得Unsafe類的對象呢?通常采用反射機制:

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

當獲得Unsafe對象之后,就可以”為所欲為“了。下面就來看看,通過Unsafe方法,我們可以做些什么。

Unsafe的主要功能可先從根據(jù)下圖從整體上了解一下Unsafe提供的功能:

Unsafe功能概述

下面挑選重要的功能進行講解。

一、內(nèi)存管理

Unsafe的內(nèi)存管理功能主要包括:普通讀寫、volatile讀寫、有序?qū)懭搿⒅苯硬僮鲀?nèi)存等分配內(nèi)存與釋放內(nèi)存的功能。

普通讀寫

Unsafe可以讀寫一個類的屬性,即便這個屬性是私有的,也可以對這個屬性進行讀寫。

// 獲取內(nèi)存地址指向的整數(shù)
public native int getInt(Object var1, long var2);

// 將整數(shù)寫入指定內(nèi)存地址
public native void putInt(Object var1, long var2, int var4);

getInt用于從對象的指定偏移地址處讀取一個int。putInt用于在對象指定偏移地址處寫入一個int。其他原始類型也提供有對應(yīng)的方法。

另外,Unsafe的getByte、putByte方法提供了直接在一個地址上進行讀寫的功能。

volatile讀寫

普通的讀寫無法保證可見性和有序性,而volatile讀寫就可以保證可見性和有序性。

// 獲取內(nèi)存地址指向的整數(shù),并支持volatile語義
public native int getIntVolatile(Object var1, long var2);

// 將整數(shù)寫入指定內(nèi)存地址,并支持volatile語義
public native void putIntVolatile(Object var1, long var2, int var4);

volatile讀寫要保證可見性和有序性,相對普通讀寫更加昂貴。

有序?qū)懭?/h4>

有序?qū)懭胫槐WC寫入的有序性,不保證可見性,就是說一個線程的寫入不保證其他線程立馬可見。

// 將整數(shù)寫入指定內(nèi)存地址、有序或者有延遲的方法
public native void putOrderedInt(Object var1, long var2, int var4);

而與volatile寫入相比putOrderedXX寫入代價相對較低,putOrderedXX寫入不保證可見性,但是保證有序性,所謂有序性,就是保證指令不會重排序。

直接操作內(nèi)存

Unsafe提供了直接操作內(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)存復制
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
// 清除內(nèi)存
public native void freeMemory(long var1);

對應(yīng)操作內(nèi)存,也提供了一些獲取內(nèi)存信息的方法:

// 獲取內(nèi)存地址
public native long getAddress(long var1);

public native int addressSize();

public native int pageSize();

值得注意的是:利用copyMemory方法可以實現(xiàn)一個通用的對象拷貝方法,無需再對每一個對象都實現(xiàn)clone方法,但只能做到對象淺拷貝。

二、非常規(guī)對象實例化

通常,我們通過new或反射來實例化對象,而Unsafe類提供的allocateInstance方法,可以直接生成對象實例,且無需調(diào)用構(gòu)造方法和其他初始化方法。

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

// 直接生成對象實例,不會調(diào)用這個實例的構(gòu)造方法
public native Object allocateInstance(Class<?> var1) throws InstantiationException;

三、類加載

通過以下方法,可以實現(xiàn)類的定義、創(chuàng)建等操作。

// 方法定義一個類,用于動態(tài)地創(chuàng)建類
public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);

// 動態(tài)的創(chuàng)建一個匿名內(nèi)部類
public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);

// 判斷是否需要初始化一個類
public native boolean shouldBeInitialized(Class<?> var1);

// 保證已經(jīng)初始化過一個類
public native void ensureClassInitialized(Class<?> var1);

四、偏移量相關(guān)

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

// 獲取靜態(tài)屬性Field在對象中的偏移量,讀寫靜態(tài)屬性時必須獲取其偏移量
public native long staticFieldOffset(Field var1);
// 獲取非靜態(tài)屬性Field在對象實例中的偏移量,讀寫對象的非靜態(tài)屬性時會用到這個偏移量
public native long objectFieldOffset(Field var1);
// 返回Field所在的對象
public native Object staticFieldBase(Field var1);
// 返回數(shù)組中第一個元素實際地址相對整個數(shù)組對象的地址的偏移量
public native int arrayBaseOffset(Class<?> var1);
// 計算數(shù)組中第一個元素所占用的內(nèi)存空間
public native int arrayIndexScale(Class<?> var1);

五、數(shù)組操作

數(shù)組操作提供了以下方法:

// 獲取數(shù)組第一個元素的偏移地址
public native int arrayBaseOffset(Class<?> var1);
// 獲取數(shù)組中元素的增量地址
public native int arrayIndexScale(Class<?> var1);

arrayBaseOffset與arrayIndexScale配合起來使用,就可以定位數(shù)組中每個元素在內(nèi)存中的位置。

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

六、線程調(diào)度

線程調(diào)度相關(guān)方法如下:

// 喚醒線程
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方法將線程進行掛起, 線程將一直阻塞到超時或中斷條件出現(xiàn)。unpark方法可以終止一個掛起的線程,使其恢復正常。

整個并發(fā)框架中對線程的掛起操作被封裝在LockSupport類中,LockSupport類中有各種版本pack方法,但最終都調(diào)用了Unsafe.park()方法。

七、CAS操作

Unsafe類的CAS操作可能是使用最多的方法。它為Java的鎖機制提供了一種新的解決辦法,比如AtomicInteger等類都是通過該方法來實現(xiàn)的。compareAndSwap方法是原子的,可以避免繁重的鎖機制,提高代碼效率。

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一般用于樂觀鎖,它在Java中有廣泛的應(yīng)用,ConcurrentHashMap,ConcurrentLinkedQueue中都有用到CAS來實現(xiàn)樂觀鎖。

八、內(nèi)存屏障

JDK8新引入了用于定義內(nèi)存屏障、避免代碼重排的方法:

// 保證在這個屏障之前的所有讀操作都已經(jīng)完成
public native void loadFence();

// 保證在這個屏障之前的所有寫操作都已經(jīng)完成
public native void storeFence();

// 保證在這個屏障之前的所有讀寫操作都已經(jīng)完成
public native void fullFence();

九、其他

當然,Unsafe類中還提供了大量其他的方法,比如上面提到的CAS操作,以AtomicInteger為例,當我們調(diào)用getAndIncrement、getAndDecrement等方法時,本質(zhì)上調(diào)用的就是Unsafe的getAndAddInt方法。

public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}

在實踐的過程中,如果閱讀其他框架或類庫實現(xiàn),當發(fā)現(xiàn)用到Unsafe類,可對照該類的整體功能,結(jié)合應(yīng)用場景進行分析,即可大概了解其功能。

小結(jié)

經(jīng)過本文的分析,想必大家在閱讀源碼時,再遇到Unsafe類的調(diào)用,一定大概猜出它是用來干什么的。使用Unsafe類的主要目的大多數(shù)情況下是為了提升運行效率、增強功能。但同時也面臨著出錯、內(nèi)存管理等風險。只有深入了解,且有必要的情況下才建議使用。

責任編輯:武曉燕 來源: 程序新視界
相關(guān)推薦

2024-01-19 14:45:36

ApacheDoris架構(gòu)

2016-09-22 16:47:55

iOSAndroidWindows Pho

2022-04-08 07:52:00

架構(gòu)多機房多活

2018-07-24 15:22:30

區(qū)塊鏈數(shù)字貨幣比特幣

2019-10-29 15:00:26

12306架構(gòu)高并發(fā)

2020-07-20 07:55:53

微信支付架構(gòu)

2018-04-16 11:34:59

2020-11-20 09:23:01

高可用異地淘寶

2020-07-17 11:28:24

App信息泄露個人信息

2022-03-28 18:08:50

通信網(wǎng)絡(luò)綠色通信節(jié)能減排

2009-06-15 18:20:27

2024-06-12 09:44:09

2019-08-01 15:06:49

離職成本員工

2013-09-24 10:20:35

代碼代碼異味

2022-09-23 08:47:01

DMA網(wǎng)卡CPU

2020-08-05 07:00:00

SSD硬盤存儲

2018-04-04 09:14:03

2022-07-10 14:59:57

機器學習人工智能預(yù)測模型

2016-10-25 09:25:36

大數(shù)據(jù)樓市走勢

2022-09-01 21:02:31

手機衛(wèi)星5G
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 久草欧美 | 91精品国产欧美一区二区 | 国产在线一区二区三区 | 中文字幕第十五页 | 久久99蜜桃综合影院免费观看 | 国产午夜在线观看 | 日本亚洲欧美 | 黄色欧美在线 | 亚洲国产精品久久 | 在线欧美a | 久在线| 国产伦精品一区二区三区视频金莲 | 欧美男人天堂 | 91精品国产综合久久久久久蜜臀 | 日韩欧美一级 | 91精品国产综合久久久动漫日韩 | 久久国产免费看 | 欧美国产日韩在线观看成人 | 国产激情毛片 | 色婷婷av777 av免费网站在线 | 亚洲视频免费在线播放 | 亚洲 成人 在线 | av大片| 91网在线观看 | 日本成人综合 | 国产精品一区二区三级 | 久久国产亚洲精品 | 精品一区二区三区中文字幕 | 99视频久| 国产ts人妖系列高潮 | 日韩中文一区二区三区 | av黄色在线观看 | 久久伊人精品 | 99精品网站 | 一区二区视频在线 | 久久成人精品视频 | 久久精品国产一区二区电影 | 亚洲综合资源 | 91看片免费版 | 成人深夜福利在线观看 | 中文字幕免费在线 |