Unsafe類,你知道多少呢?

来源:https://www.cnblogs.com/java265/archive/2022/04/11/16129279.html
-Advertisement-
Play Games

1,打包項目 把項目打成jar 2,配置idea遠程調試 我設置的是本地調試,遠程伺服器設置為遠程的伺服器和埠即可。 3, 伺服器啟動項目 啟動項目: java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 - ...


 在一些常用的中間件中,我們經常看見Unsafe類(sun.misc.Unsafe)的使用,如Netty、Cassandra、Hadoop、Kafka等,那麼你知道Unsafe類的功能嗎?
下文筆者將一一道來,如下所示:

Unsafe類的功能簡介

Unsafe類在sun.misc包下
Unsafe類不是Java標準類,一般的開發者不會涉及此類的開發
Unsafe類可提高java的運行效率

Unsafe類的功能:
     使我們可跳過JVM,使java語言擁有c語言指針一樣的能力,
	  如:操作記憶體空間,CAS,併發編程等能力

Unsafe類簡介

Unsafe類使用“final”修改,不可以繼承,並且構造函數是private,所以我們只能使用靜態方法獲取它的實例
例:

 private Unsafe() {
    }
​
@CallerSensitive
public static Unsafe getUnsafe() {
  Class var0 = Reflection.getCallerClass();
  if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
         throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }
從getUnsafe()方法中,我們可以得知,
只有主類載入器才可以調用此方法,否則就會拋出異常

例:調用getUnsafe方法返回Unsafe

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

Unsafe的主要功能

 


記憶體管理

Unsafe的記憶體管理功能主要包括
   普通讀寫、volatile讀寫、有序寫入、直接操作記憶體等分配記憶體與釋放記憶體的功能
普通讀寫

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

//獲取記憶體地址指向的整數
public native int getInt(Object var1, long var2);
       getInt用於從對象的指定偏移地址處讀取一個int
​
//將整數寫入指定記憶體地址
public native void putInt(Object var1, long var2, int var4);
      putInt用於在對象指定偏移地址處寫入一個int。其他原始類型也提供有對應的方法

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

volatile讀寫
  普通的讀寫無法保證可見性和有序性,而volatile讀寫就可以保證可見性和有序性。
// 獲取記憶體地址指向的整數,並支持volatile語義
public native int getIntVolatile(Object var1, long var2);
​
// 將整數寫入指定記憶體地址,並支持volatile語義
public native void putIntVolatile(Object var1, long var2, int var4);
   volatile讀寫要保證可見性和有序性,相對普通讀寫更加昂貴

有序寫入
   有序寫入只保證寫入的有序性,不保證可見性
   就是說一個線程的寫入不保證其他線程立馬可見。
// 將整數寫入指定記憶體地址、有序或者有延遲的方法
public native void putOrderedInt(Object var1, long var2, int var4);

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

直接操作記憶體
Unsafe提供了直接操作記憶體的能力:
// 分配記憶體
public native long allocateMemory(long var1);
// 重新分配記憶體
public native long reallocateMemory(long var1, long var3);
// 記憶體初始化
public native void setMemory(long var1, long var3, byte var5);
// 記憶體複製
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
// 清除記憶體
public native void freeMemory(long var1);
​
對應操作記憶體,也提供了一些獲取記憶體信息的方法:
// 獲取記憶體地址
public native long getAddress(long var1);
​
public native int addressSize();
​
public native int pageSize();

註意事項:
 使用copyMemory方法可以實現一個通用的對象拷貝方法
  無需再對每一個對象都實現clone方法,但只能做到對象淺拷貝

"非常規”對象實例化

通常情況下,我們使用new關鍵字實例化一個對象,但是Unsafe類中有一個方法allocateInstance,可直接生成對象實例,無需構造方法和其它初始化方法

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

類載入

通過以下方法,可以實現類的定義、創建等操作。
// 方法定義一個類,用於動態地創建類
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 boolean shouldBeInitialized(Class<?> var1);

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

偏移量相關

Unsafe提供以下方法獲取對象的指針,通過對指針進行偏移,不僅可以直接修改指針指向的數據(即使它們是私有的),甚至可以找到JVM已經認定為垃圾、可以進行回收的對象。
// 獲取靜態屬性Field在對象中的偏移量,讀寫靜態屬性時必須獲取其偏移量
public native long staticFieldOffset(Field var1);
// 獲取非靜態屬性Field在對象實例中的偏移量,讀寫對象的非靜態屬性時會用到這個偏移量
public native long objectFieldOffset(Field var1);
// 返回Field所在的對象
public native Object staticFieldBase(Field var1);
// 返回數組中第一個元素實際地址相對整個數組對象的地址的偏移量
public native int arrayBaseOffset(Class<?> var1);
// 計算數組中第一個元素所占用的記憶體空間
public native int arrayIndexScale(Class<?> var1);

數組操作

數組操作提供了以下方法:
// 獲取數組第一個元素的偏移地址
public native int arrayBaseOffset(Class<?> var1);
// 獲取數組中元素的增量地址
public native int arrayIndexScale(Class<?> var1);

線程調度

線程調度相關方法如下:
// 喚醒線程
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方法可以終止一個掛起的線程,使其恢復正常

CAS操作

Unsafe類的CAS操作可能是使用最多的方法
它為Java的鎖機制提供了一種新的解決辦法,
如AtomicInteger等類都是通過該方法來實現的
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中有廣泛的應用,ConcurrentHashMap,ConcurrentLinkedQueue中都有用到CAS來實現樂觀鎖。

記憶體屏障

JDK8新引入了用於定義記憶體屏障、避免代碼重排的方法:
// 保證在這個屏障之前的所有讀操作都已經完成
public native void loadFence();

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

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

其他

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

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

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

轉自:http://www.java265.com/JavaCourse/202204/2835.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 內容介紹 介紹 JavaSE 基礎的基本語法知識,不會包含特別難以理解或更深層次的內容,通俗易懂。 前提 本書的所有例子使用 JDK8 在 Windows10 系統下完成,所以預設使用 exe;若你與我的不一致,快捷鍵、源碼都有可能不同,但網上無償資源十分的多,搜索瞭解不同之處即可。 受眾人群 ...
  • 前言 為什麼要學習python?是因為不僅很多工作需要用到python,同時我們可以利用python做很多好玩兒的事兒。 今天就來教大家如何利用python製作動態二維碼。 代碼說明:我們以小豬佩奇gif圖片為例,如果我們利用的背景圖是gif動態圖,生成的就是動態二維碼。如果利用的背景是靜態 圖,生 ...
  • 在日常開發中,一個優雅的API,必須提供簡單明瞭的響應值,然後根據狀態碼就可以大概知道問題的所在。這裡主要整理一下HTTP狀態碼和自定義狀態碼。 1、HTTP狀態碼 當瀏覽者訪問一個網頁時,瀏覽者的瀏覽器會向網頁所在伺服器發出請求。當瀏覽器接收並顯示網頁前,此網頁所在的伺服器會返回一個包含 HTTP ...
  • 在Word插入分頁符可以在指定段落後插入,也可以在特定文本位置處插入。本文,將以Java代碼來操作以上兩種文檔分頁需求。下麵是詳細方法及步驟。 【程式環境】 在程式中導入jar,如下兩種方法: 方法1:手動引入。將 Free Spire.Doc for Java 下載到本地,解壓,找到lib文件夾下 ...
  • 來源:juejin.cn/post/6844904142960328718 前言 剛剛與同事開了一個分享會,筆者分享了一些了代碼設計模式相關的內容。 以及復盤了一下項目中有些複雜的業務場景,為什麼沒有很好的應用到設計模式。 業務雖然肯定保密的,但是拋開項目,業務層面,縱觀回顧了一下筆者以往的項目, ...
  • 基於docker搭建laravel項目 公司PHP項目是Laravel框架寫的,目前環境需要通過docker來部署一下。網上學習了一下相關知識。整理後做一個筆記。用到定時任務crontab與進程管理supervisor。 主要參考項目: 《docker完美搭建laravel運行環境》參考1 項目時間 ...
  • 今天給大家分享一個數據平均值的吧,好像從來沒有分享過這個內容。 以問題為導向利用Python幫助我們解決在科研中遇到的問題。最近有同學在處理TRMM降水數據的時候,說是要提取每個月的均 值出來。數據格式是tif柵格,目的也是非常明確的:提取多個tif的降水柵格均值出來。 剛纔看了一下TRMM的計劃說 ...
  • 在學習python之前我們可以先學習一些Linux的簡單語法,幫助我們對python語句的編譯和執行有一個更好的理解,同時如果我們以後開發的python程式需要用到伺服器,可以直接用Linux搭建。 接下來我們就可以開始學習python了,python、Java和PHP等語言被稱為高級語言,C語言和 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...