偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

一半是天使一半是魔鬼的Unsafe類詳解

開發(fā) 后端
如果你學(xué)習(xí)了一些java并發(fā)包里面的類源碼的話,對這個Unsafe類一定不陌生,整個java并發(fā)包底層實現(xiàn)的核心就是它,在很久之前盛傳著這個類將要在jdk9移除,事實上如果移除了那么一大批框架將會消失,比如說赫赫有名的Netty框架。

 [[355691]]

可能我們會奇怪,java中竟然給一個類起名字叫做“不安全”。慢慢看,你就會發(fā)現(xiàn)這個類的神奇之處,雖然功能很強大,但是的確不那么安全。

一、簡單介紹

首先在Oracle的Jdk8無法獲取到sun.misc包的源碼,想看此包的源碼可以直接下載openjdk。

1、預(yù)備工作

openjdk的源碼我下載的是openjdk-8u40-src-b25-10_feb_2015,有需要的可以私信我,如果是我公眾號粉絲,我會直接附加上這個百度云資源。在下載完成之后,然后就可以直接導(dǎo)入我們的eclipse了。

windows->preference->installed jres->選中jre->edit->rt.jar->source attachment->external folders->openjdk源碼路徑。此時就可以查看我們的Unsafe類的源碼了。

2、簡介說明

如果你學(xué)習(xí)了一些java并發(fā)包里面的類源碼的話,對這個Unsafe類一定不陌生,整個java并發(fā)包底層實現(xiàn)的核心就是它,在很久之前盛傳著這個類將要在jdk9移除,事實上如果移除了那么一大批框架將會消失,比如說赫赫有名的Netty框架。最終jdk9出現(xiàn)的時候也只是對其進(jìn)行了改進(jìn)和優(yōu)化。不過這也再一次說明了這個類的重要地位。

為什么說它一半是天使一半是魔鬼呢?要回答這個問題,我們還是要從其特性來解釋。

Unsafe類使Java擁有了像C語言的指針一樣操作內(nèi)存空間的能力,一旦能夠直接操作內(nèi)存,這也就意味著(1)不受jvm管理,也就意味著無法被GC,需要我們手動GC,稍有不慎就會出現(xiàn)內(nèi)存泄漏。

(2)Unsafe的不少方法中必須提供原始地址(內(nèi)存地址)和被替換對象的地址,偏移量要自己計算,一旦出現(xiàn)問題就是JVM崩潰級別的異常,會導(dǎo)致整個JVM實例崩潰,表現(xiàn)為應(yīng)用程序直接crash掉。

(3)直接操作內(nèi)存,也意味著其速度更快,在高并發(fā)的條件之下能夠很好地提高效率。

因此,從上面三個角度來看,雖然在一定程度上提升了效率但是也帶來了指針的不安全性。

下面我們深入到源碼中看看,提供了什么方法直接操作內(nèi)存。

二、源碼分析

Unsafe中一共有82個public native修飾的方法,還有幾十個基于這82個public native方法的其他方法。這些方法大體可以歸結(jié)為以下幾類:

(1)初始化操作

(2)操作對象屬性

(3)操作數(shù)組元素

(4)內(nèi)存管理

(5)內(nèi)存屏障

(6)線程掛起和回復(fù)

(7)CAS機制

下面我們對這些方法盡進(jìn)行一個大致的分析。

1、初始化

  1. //1、注冊native方法,是的Unsafe類可以操作C語言 
  2.  private static native void registerNatives(); 
  3.  static { 
  4.      registerNatives(); 
  5.      sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); 
  6.  } 
  7.  //2、構(gòu)造方法 
  8.  private Unsafe() {} 
  9.  //3、初始化方法 
  10.  private static final Unsafe theUnsafe = new Unsafe(); 
  11.  //4、初始化方法實現(xiàn) 
  12.  @CallerSensitive 
  13.  public static Unsafe getUnsafe() { 
  14.      Class<?> caller = Reflection.getCallerClass(); 
  15.      if (!VM.isSystemDomainLoader(caller.getClassLoader())) 
  16.          throw new SecurityException("Unsafe"); 
  17.      return theUnsafe; 
  18.  } 

在這里我們看到Unsafe的初始化方法主要是通過getUnsafe方法的單例模式實現(xiàn)的,調(diào)用JVM本地方法registerNatives()和sun.reflect.Reflection,通過Reflection的getCallerClass判斷當(dāng)前調(diào)用的類是否是主類加載器(BootStrap classLoader)加載的,否則的話拋出一個SecurityException。這也證明了一個問題,那就是只有由主類加載器(BootStrap classLoader)加載的類才能調(diào)用這個類中的方法。

2、操作屬性方法

(1)public native Object getObject(Object o, long offset);

通過給定的Java變量獲取引用值。這里實際上是獲取一個Java對象o中,獲取偏移地址為offset的屬性的值,此方法可以突破修飾符的抑制,也就是無視private、protected和default修飾符。類似的方法有g(shù)etInt、getDouble等等。同理還有putObject方法。

(2)public native Object getObjectVolatile(Object o, long offset);

強制從主存中獲取屬性值。類似的方法有g(shù)etIntVolatile、getDoubleVolatile等等。同理還有putObjectVolatile。

(3)public native void putOrderedObject(Object o, long offset, Object x);

設(shè)置o對象中offset偏移地址offset對應(yīng)的Object型field的值為指定值x。這是一個有序或者有延遲的putObjectVolatile方法,并且不保證值的改變被其他線程立即看到。只有在field被volatile修飾并且期望被修改的時候使用才會生效。類似的方法有putOrderedInt和putOrderedLong。

(4)public native long staticFieldOffset(Field f);

返回給定的靜態(tài)屬性在它的類的存儲分配中的位置(偏移地址)。

(5)public native long objectFieldOffset(Field f);

返回給定的非靜態(tài)屬性在它的類的存儲分配中的位置(偏移地址)。

(6)public native Object staticFieldBase(Field f);

返回給定的靜態(tài)屬性的位置,配合staticFieldOffset方法使用。

3、操作數(shù)組

(1)public native int arrayBaseOffset(Class arrayClass);

返回數(shù)組類型的第一個元素的偏移地址(基礎(chǔ)偏移地址)。

(2)public native int arrayIndexScale(Class arrayClass);

返回數(shù)組中元素與元素之間的偏移地址的增量。

這兩個方法配合使用就可以定位到任何一個元素的地址。

4、內(nèi)存管理

(1)public native int addressSize();

獲取本地指針的大小(單位是byte),通常值為4或者8。常量ADDRESS_SIZE就是調(diào)用此方法。

(2)public native int pageSize();

獲取本地內(nèi)存的頁數(shù),此值為2的冪次方。

(3)public native long allocateMemory(long bytes);

分配一塊新的本地內(nèi)存,通過bytes指定內(nèi)存塊的大小(單位是byte),返回新開辟的內(nèi)存的地址。

(4)public native long reallocateMemory(long address, long bytes);

通過指定的內(nèi)存地址address重新調(diào)整本地內(nèi)存塊的大小,調(diào)整后的內(nèi)存塊大小通過bytes指定(單位為byte)。

(5)public native void setMemory(Object o, long offset, long bytes, byte value);

將給定內(nèi)存塊中的所有字節(jié)設(shè)置為固定值(通常是0)。

5、線程掛起和恢復(fù)

(1)public native void unpark(Object thread);

釋放被park創(chuàng)建的在一個線程上的阻塞。由于其不安全性,因此必須保證線程是存活的。

(2)public native void park(boolean isAbsolute, long time);`

阻塞當(dāng)前線程,一直等道unpark方法被調(diào)用。

6、內(nèi)存屏障

(1)public native void loadFence();

在該方法之前的所有讀操作,一定在load屏障之前執(zhí)行完成。

(2)public native void storeFence();

在該方法之前的所有寫操作,一定在store屏障之前執(zhí)行完成

(3)public native void fullFence();

在該方法之前的所有讀寫操作,一定在full屏障之前執(zhí)行完成,這個內(nèi)存屏障相當(dāng)于上面兩個(load屏障和store屏障)的合體功能。

7、CAS機制

  1. public final native boolean compareAndSwapObject( 
  2.     Object o, long offset, Object expected, Object x); 
  3. public final native boolean compareAndSwapInt( 
  4.     Object o, long offset,int expected, int x); 
  5. public final native boolean compareAndSwapLong( 
  6.     Object o, long offset, long expected,long x); 

這個Unsafe類其實是貫穿到整個java并發(fā)包體系中的,不管是你看原子包還是lock包底部都有這樣的一個類,我們需要記住的不是每一個方法,而是上面七類的標(biāo)題。也就是具體有什么功能。

三、使用

說了這么久的源碼在這里才介紹其使用,是因為官方并不推薦我們使用,也就是說我們無法直接new出來一個Unsafe類出來,那我們該如何使用呢?在很久之前我曾寫過一篇介紹java反射機制的文章,沒錯就是這個反射機制,牛的不行。Unsafe就可以通過反射機制來獲取。

  1. public class UnsafeTest { 
  2.     public static void main(String[] args) throws Exception { 
  3.         //這里的theUnsafe就是我們源碼中的那個theUnsafe 
  4.         Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); 
  5.         theUnsafe.setAccessible(true); 
  6.         Unsafe unsafe = (Unsafe) theUnsafe.get(null); 
  7.  
  8.         //1、創(chuàng)建對象實例 
  9.         Author author = (Author) unsafe.allocateInstance(Author.class); 
  10.         //2、操作對象的屬性 
  11.         Field ageField = Author.class.getDeclaredField("age"); 
  12.         long fieldOffset = unsafe.objectFieldOffset(ageField); 
  13.         //3、操作數(shù)組 
  14.         String[] strings = new String[]{"1""2""3"}; 
  15.         long i = unsafe.arrayBaseOffset(String[].class); 
  16.         //4、操作內(nèi)存 
  17.         long address = unsafe.allocateMemory(8L);         
  18.     } 

在這里只是給出一些簡單的例子,其用法可以參照源碼分析中那七個方向。

注意:面試時有個小技巧,對于java語言特性而言,有很多違背java語言設(shè)計的功能都可以用這個類去回答

本文轉(zhuǎn)載自微信公眾號「愚公要移山」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系愚公要移山公眾號。

 

責(zé)任編輯:武曉燕 來源: 愚公要移山
相關(guān)推薦

2015-07-27 10:24:01

蘋果中國

2018-06-03 08:49:21

2013-11-27 15:48:56

移動中間件廠商

2016-12-16 13:07:30

云存儲運營混合云

2013-02-25 10:11:35

4GLTE商用網(wǎng)絡(luò)

2009-04-09 08:46:02

iphone蘋果移動OS

2022-02-14 16:17:14

垃圾郵件網(wǎng)絡(luò)釣魚

2010-09-17 16:21:33

系統(tǒng)升級

2017-02-24 13:53:38

HTTPS流量互聯(lián)網(wǎng)

2021-12-09 08:54:20

數(shù)組數(shù)字排序

2017-02-27 16:54:20

HTTPS網(wǎng)絡(luò)流量互聯(lián)網(wǎng)

2019-10-10 10:54:16

戴爾

2009-04-30 09:01:25

微軟操作系統(tǒng)Windows 7

2011-08-17 10:53:16

Firefox 7

2020-07-13 09:48:58

云計算云安全數(shù)據(jù)

2025-05-09 08:20:37

數(shù)據(jù)類Kotlin代碼

2019-01-07 14:32:17

iPhone XR蘋果手機

2010-01-15 09:39:43

甲骨文Sun

2009-05-21 08:46:11

臺積電返崗員工關(guān)懷金

2011-11-07 10:06:28

惠普ARM服務(wù)器Moonshot
點贊
收藏

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