最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?JNI的高級(jí)用法示例詳解

 更新時(shí)間:2025年11月26日 08:53:33   作者:猩火燎猿  
JNI是Java高級(jí)應(yīng)用中不可或缺的技術(shù)之一,它允許Java程序與本地代碼進(jìn)行交互,大大拓寬了Java應(yīng)用的范圍和性能,這篇文章主要介紹了Java?JNI高級(jí)用法的相關(guān)資料,需要的朋友可以參考下

1. native 層多線程與 JVM 交互

1.1 native 層啟動(dòng)線程

在 JNI 中,native 層可以創(chuàng)建自己的線程(如 pthread、std::thread),但這些線程不是 JVM 線程,不能直接訪問(wèn) JVM 資源。
必須 attach 到 JVM,才能安全調(diào)用 Java 對(duì)象或方法。

1.2 attach/detach 線程

JavaVM* jvm; // 全局保存 JavaVM 指針

// 線程函數(shù)
void* thread_func(void* arg) {
    JNIEnv* env;
    // 線程 attach 到 JVM
    (*jvm)->AttachCurrentThread(jvm, (void**)&env, NULL);

    // 可以安全訪問(wèn) Java 對(duì)象和方法
    // ...

    // 線程結(jié)束前 detach
    (*jvm)->DetachCurrentThread(jvm);
    return NULL;
}

注意

  • attach 后才能用 JNI API。
  • detach 前必須釋放所有局部引用。
  • 多線程下要小心全局引用的并發(fā)安全(加鎖)。

1.3 native 層回調(diào) Java(多線程)

  • 通過(guò)全局引用保存回調(diào)對(duì)象,native 線程 attach 后用 CallVoidMethod/CallStaticMethod 調(diào)用 Java 方法。
  • 回調(diào)后及時(shí)刪除局部引用,防止內(nèi)存泄漏。

2. 復(fù)雜對(duì)象的 JNI 傳遞與構(gòu)造

2.1 Java 傳對(duì)象給 native

Java:

public class Person {
    public int age;
    public String name;
}
public native void processPerson(Person p);

C:

jclass cls = (*env)->GetObjectClass(env, person);
jfieldID fid_age = (*env)->GetFieldID(env, cls, "age", "I");
jint age = (*env)->GetIntField(env, person, fid_age);

jfieldID fid_name = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
jstring jname = (jstring)(*env)->GetObjectField(env, person, fid_name);
// 轉(zhuǎn)換為 C 字符串
const char* cname = (*env)->GetStringUTFChars(env, jname, NULL);
// ...
(*env)->ReleaseStringUTFChars(env, jname, cname);

2.2 native 構(gòu)造 Java 對(duì)象并返回

C:

jclass cls = (*env)->FindClass(env, "Person");
jmethodID ctor = (*env)->GetMethodID(env, cls, "<init>", "()V");
jobject obj = (*env)->NewObject(env, cls, ctor);

jfieldID fid_age = (*env)->GetFieldID(env, cls, "age", "I");
(*env)->SetIntField(env, obj, fid_age, 25);

// 返回 obj 給 Java
return obj;

2.3 復(fù)雜數(shù)組/集合的傳遞

  • 對(duì)于 Java List/Map,native 層一般用反射方式訪問(wèn)元素,效率較低。
  • 性能敏感時(shí)建議用數(shù)組(如 int[]、Object[]),native 層用 GetObjectArrayElement 操作。

3. Java Lambda 與 JNI

3.1 Java Lambda 本質(zhì)

Lambda 是編譯期自動(dòng)生成的匿名類對(duì)象,實(shí)現(xiàn)了目標(biāo)接口(如 Runnable、Function)。
JNI 層看到的是普通的 Java 對(duì)象。

3.2 JNI 層調(diào)用 Lambda

  • JNI 層可接收 lambda 作為參數(shù),只要用接口類型聲明。
  • JNI 通過(guò)反射/接口調(diào)用,調(diào)用 lambda 的方法(如 run、apply)。

示例:

public native void useCallback(Runnable r);
useCallback(() -> System.out.println("Hello from Lambda!"));

C:

jclass cls = (*env)->GetObjectClass(env, runnable);
jmethodID mid = (*env)->GetMethodID(env, cls, "run", "()V");
(*env)->CallVoidMethod(env, runnable, mid);

3.3 局限與注意

  • Lambda 不能直接在 native 層定義或?qū)崿F(xiàn)。
  • native 層只能把 lambda 當(dāng)作普通對(duì)象處理,不能享受 Java 層類型推斷等語(yǔ)法糖。
  • 性能敏感場(chǎng)景下,頻繁回調(diào) lambda 會(huì)有 JNI 橋接開(kāi)銷。

4. JNI 性能基準(zhǔn)測(cè)試與優(yōu)化

4.1 性能測(cè)試方法

  • 使用 JMH(Java Microbenchmark Harness)寫基準(zhǔn)測(cè)試,比較 Java 方法、JNI 方法、JNA 方法的調(diào)用耗時(shí)。
  • 典型測(cè)試:循環(huán)調(diào)用百萬(wàn)次,測(cè)量總耗時(shí)。

JMH 示例:

@Benchmark
public void testJavaAdd() {
    int a = 1, b = 2;
    int c = a + b;
}

@Benchmark
public void testJNIAdd() {
    nativeAdd(1, 2);
}

4.2 常見(jiàn)性能瓶頸

  • JNI 方法調(diào)用有固定的橋接開(kāi)銷(幾十到幾百納秒)。
  • 數(shù)據(jù)類型轉(zhuǎn)換(如字符串、數(shù)組)開(kāi)銷大。
  • 頻繁創(chuàng)建/釋放引用、反射操作等會(huì)拖慢性能。

4.3 優(yōu)化建議

  • 減少 JNI 調(diào)用次數(shù):能批量處理就批量,避免頻繁小操作。
  • 緩存 class/methodID:避免每次都查找。
  • 用直接緩沖區(qū)(DirectByteBuffer):大數(shù)據(jù)傳遞更高效。
  • 避免不必要的數(shù)據(jù)拷貝:如數(shù)組可用 GetPrimitiveArrayCritical。
  • 合理管理引用:用完及時(shí)釋放局部/全局引用。
  • 選擇合適的傳遞方式:復(fù)雜結(jié)構(gòu)建議序列化或用 protobuf/C結(jié)構(gòu)體映射。

5. 典型面試題與實(shí)戰(zhàn)解析

  • native 層多線程調(diào)用 Java 方法有什么注意事項(xiàng)?

    • 線程必須 attach/detach,回調(diào)對(duì)象需全局引用,注意并發(fā)安全。
  • 如何從 native 層構(gòu)造 Java 對(duì)象并返回?

    • 用 FindClass、GetMethodID、NewObject、SetXXXField。
  • lambda 作為回調(diào)參數(shù)傳給 native,JNI 如何調(diào)用?

    • 當(dāng)作接口對(duì)象,反射調(diào)用相應(yīng)方法(如 run/apply)。
  • JNI 性能瓶頸主要在哪?如何優(yōu)化?

    • 橋接和數(shù)據(jù)轉(zhuǎn)換開(kāi)銷大,建議批量處理、緩存 methodID、用直接緩沖區(qū)。

6. native 層多線程最佳實(shí)踐

6.1 多線程安全 attach/detach

  • 獲取 JavaVM 指針:在 JNI_OnLoad 里全局保存 JavaVM 指針,供所有 native 線程使用。
  • 線程 attach:每個(gè) native 線程首次需要 attach 到 JVM,獲得 JNIEnv 指針。
  • 線程 detach:線程退出前 detach,避免 JVM 資源泄露。

示例:

JavaVM* g_jvm = NULL;

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    g_jvm = vm;
    return JNI_VERSION_1_6;
}

void* worker(void* arg) {
    JNIEnv* env;
    if ((*g_jvm)->AttachCurrentThread(g_jvm, (void**)&env, NULL) == 0) {
        // 使用 env 調(diào)用 Java 方法
        // ...
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }
    return NULL;
}

6.2 并發(fā)安全的回調(diào)

  • 回調(diào)對(duì)象需用 NewGlobalRef 創(chuàng)建全局引用,避免被 GC 回收。
  • 回調(diào)時(shí)加鎖(如 pthread_mutex),確保多線程安全。
  • 回調(diào)后及時(shí) DeleteGlobalRef,避免內(nèi)存泄漏。

7. 復(fù)雜對(duì)象高效傳遞與映射

7.1 批量數(shù)據(jù)結(jié)構(gòu)傳遞

  • 對(duì)于大量數(shù)據(jù)(如點(diǎn)、向量、結(jié)構(gòu)體),建議用 ByteBuffer 或直接數(shù)組傳遞,native 層按內(nèi)存結(jié)構(gòu)解析。
  • 可用 Java 的 DirectByteBuffer,native 層用 GetDirectBufferAddress 獲得指針,零拷貝高性能。

Java:

ByteBuffer buf = ByteBuffer.allocateDirect(1024);
nativeProcessBuffer(buf);

C:

void JNICALL nativeProcessBuffer(JNIEnv* env, jobject obj, jobject buffer) {
    void* ptr = (*env)->GetDirectBufferAddress(env, buffer);
    // 直接操作內(nèi)存
}

7.2 復(fù)雜對(duì)象序列化

  • 對(duì)于復(fù)雜 Java 對(duì)象(如 Map/List),可以用 JSON、protobuf、flatbuffers 序列化后傳遞到 native 層,native 層反序列化為 C 結(jié)構(gòu)體。
  • 這樣可以避免 JNI 的反射遍歷,提高性能和靈活性。

8. lambda 在高性能場(chǎng)景下的實(shí)戰(zhàn)建議

8.1 場(chǎng)景分析

  • Java 層傳遞 lambda 作為回調(diào),native 層保存并在事件發(fā)生時(shí)回調(diào)。
  • 性能敏感時(shí),建議只傳遞接口對(duì)象,避免頻繁回調(diào)和反射。

8.2 高效回調(diào)設(shè)計(jì)

  • native 層只保存接口對(duì)象的全局引用,不做多余的類型檢查。
  • 回調(diào)時(shí)直接用 methodID 調(diào)用,不用每次查找。
  • 如果回調(diào)次數(shù)極多,可設(shè)計(jì)事件隊(duì)列,由 Java 層統(tǒng)一處理,減少 JNI 交互頻率。

9. JNI 性能基準(zhǔn)測(cè)試與分析

9.1 JMH 基準(zhǔn)測(cè)試示例

@Benchmark
public void javaMethod() {
    // 普通 Java 方法
}

@Benchmark
public void jniMethod() {
    nativeMethod();
}

@Benchmark
public void jniArrayMethod() {
    nativeArrayMethod(new int[1000]);
}

測(cè)試結(jié)論

  • 普通 Java 方法最快。
  • JNI 方法有橋接開(kāi)銷,單次調(diào)用比 Java 慢幾十到幾百納秒。
  • 傳遞數(shù)組/對(duì)象時(shí),JNI 開(kāi)銷更大,建議批量處理。

9.2 優(yōu)化建議

  • 批量處理:如 1000 個(gè)點(diǎn)一次傳遞,避免 1000 次 JNI 調(diào)用。
  • 緩存 class/methodID:只查找一次,后續(xù)直接用。
  • DirectByteBuffer/序列化:大數(shù)據(jù)零拷貝或高效解析。
  • 避免反射和頻繁創(chuàng)建引用

10. JNI 在實(shí)際項(xiàng)目中的架構(gòu)建議

10.1 封裝 native 層 API

  • Java 層只暴露簡(jiǎn)單的 native 方法,參數(shù)類型盡量基礎(chǔ)(如數(shù)組、ByteBuffer)。
  • native 層用 C/C++ 封裝復(fù)雜邏輯,統(tǒng)一管理線程和資源,避免 Java 層直接暴露復(fù)雜對(duì)象。

10.2 資源和異常管理

  • 所有 native 層分配的內(nèi)存和引用都需及時(shí)釋放。
  • native 層出錯(cuò)時(shí)及時(shí) ThrowNew Java 異常,不讓 JVM 崩潰。

10.3 跨平臺(tái)適配

  • 動(dòng)態(tài)庫(kù)需分別編譯 Windows/Linux/macOS,接口保證一致性。
  • 可用 CMake/autotools 管理多平臺(tái)構(gòu)建。

11. 典型面試題解析(補(bǔ)充)

  • 如何用 JNI 實(shí)現(xiàn) Java 層的事件回調(diào)?

    • 保存回調(diào)對(duì)象的全局引用,native 事件發(fā)生時(shí) attach 線程并調(diào)用 Java 方法。
  • 批量數(shù)據(jù)高效傳遞的最佳實(shí)踐?

    • 用 DirectByteBuffer 或 protobuf 序列化,native 層直接解析內(nèi)存。
  • native 多線程并發(fā)安全的關(guān)鍵點(diǎn)?

    • attach/detach 線程,回調(diào)對(duì)象用全局引用,操作時(shí)加鎖。
  • JNI 性能優(yōu)化的核心原則?

    • 減少調(diào)用次數(shù),批量處理,緩存查找結(jié)果,零拷貝傳遞。

11. 總結(jié)

  • JNI 支持 native 層多線程、復(fù)雜對(duì)象交互、Java lambda 回調(diào)等高級(jí)用法,但需嚴(yán)格管理線程、引用和資源。
  • 性能優(yōu)化需關(guān)注調(diào)用次數(shù)、數(shù)據(jù)傳遞方式和引用管理。
  • 工程實(shí)踐中建議只在必要場(chǎng)景使用 JNI,盡量封裝好接口,簡(jiǎn)化 Java 與 native 的交互。
  • JNI 高級(jí)用法需關(guān)注多線程安全、復(fù)雜對(duì)象高效傳遞、回調(diào)機(jī)制、性能基準(zhǔn)與優(yōu)化。
  • 工程實(shí)踐中建議封裝好接口,統(tǒng)一管理資源和異常,保證跨平臺(tái)一致性和高性能。
  • 面試和項(xiàng)目中,能用 DirectByteBuffer、序列化、全局引用等技巧,往往體現(xiàn)高級(jí)水平。

到此這篇關(guān)于Java JNI的高級(jí)用法的文章就介紹到這了,更多相關(guān)Java JNI高級(jí)用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA中Collections工具類sort()排序方法

    JAVA中Collections工具類sort()排序方法

    這篇文章主要介紹了JAVA中Collections工具類sort()排序方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2016-11-11
  • SpringBoot應(yīng)用部署到Tomcat中無(wú)法啟動(dòng)的解決方法

    SpringBoot應(yīng)用部署到Tomcat中無(wú)法啟動(dòng)的解決方法

    這篇文章主要介紹了SpringBoot應(yīng)用部署到Tomcat中無(wú)法啟動(dòng)的解決方法,需要的朋友可以參考下
    2017-09-09
  • SpringBoot整合resilience4j實(shí)現(xiàn)接口限流

    SpringBoot整合resilience4j實(shí)現(xiàn)接口限流

    最近在開(kāi)發(fā)項(xiàng)目的時(shí)候,需要用到限流的功能,本文主要介紹了SpringBoot整合resilience4j實(shí)現(xiàn)接口限流,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Java使用正則提取字符串中的內(nèi)容的詳細(xì)步驟

    Java使用正則提取字符串中的內(nèi)容的詳細(xì)步驟

    這篇文章主要介紹了Java中使用正則表達(dá)式提取字符串內(nèi)容的方法,通過(guò)Pattern和Matcher類實(shí)現(xiàn),涵蓋編譯正則、查找匹配、分組捕獲、數(shù)字與郵箱提取場(chǎng)景,以及命名分組、非貪婪匹配等技巧,需要的朋友可以參考下
    2025-08-08
  • maven?傳遞依賴的實(shí)現(xiàn)

    maven?傳遞依賴的實(shí)現(xiàn)

    本文主要介紹了Maven中傳遞依賴的處理方式,如scope=compile影響依賴傳遞,使用排除不需要的依賴,以及如何通過(guò)查看依賴樹(shù)解決運(yùn)行時(shí)錯(cuò)誤,特別是在依賴排除后可能導(dǎo)致的運(yùn)行時(shí)缺少必需包的問(wèn)題,感興趣的可以了解一下
    2024-10-10
  • java list隨機(jī)抽取元素的案例

    java list隨機(jī)抽取元素的案例

    這篇文章主要介紹了java list隨機(jī)抽取元素的案例,具有很好的參考,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • 詳解SpringBean基于XML的裝配

    詳解SpringBean基于XML的裝配

    Bean的裝配可以理解為依賴關(guān)系注入,Bean的裝配方式也就是Bean 的依賴注入方式.Spring容器支持多種形式的Bean的裝配方式,如基于XML的Bean裝配,基于Annotation的Bean裝配和自動(dòng)裝配等.本文就帶大家了解SpringBean基于XML的裝配,需要的朋友可以參考下
    2021-05-05
  • Java中的ReentrantLock使用解析

    Java中的ReentrantLock使用解析

    這篇文章主要介紹了Java中的ReentrantLock使用解析,ReentrandLock即可重入鎖,可重入鎖解決的是重入鎖定的問(wèn)題,重入鎖定指的是當(dāng)一個(gè)線程執(zhí)行邏輯時(shí),需要兩次獲取鎖,而該鎖不可重入就會(huì)導(dǎo)致內(nèi)部嵌套無(wú)法獲取鎖導(dǎo)致Reentrance Lockout發(fā)生,需要的朋友可以參考下
    2023-11-11
  • JavaWeb實(shí)現(xiàn)表單提交的示例詳解

    JavaWeb實(shí)現(xiàn)表單提交的示例詳解

    這篇文章主要介紹了如何利用JavaWeb實(shí)現(xiàn)表單提交功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)JavaWeb有一定幫助,感興趣的可以了解一下
    2022-03-03
  • java TreeUtil菜單遞歸工具類

    java TreeUtil菜單遞歸工具類

    這篇文章主要為大家詳細(xì)介紹了java TreeUtil菜單遞歸工具類,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08

最新評(píng)論

阳高县| 靖远县| 岑溪市| 荔波县| 呼图壁县| 普宁市| 苍山县| 海兴县| 工布江达县| 和林格尔县| 威远县| 梨树县| 宝兴县| 独山县| 林周县| 密山市| 江山市| 长宁区| 莲花县| 全州县| 疏勒县| 乐清市| 湖南省| 亚东县| 西乌珠穆沁旗| 黄大仙区| 遂川县| 桐庐县| 尼勒克县| 清水县| 怀柔区| 越西县| 周口市| 大新县| 湘乡市| 台安县| 德昌县| 磐安县| 若尔盖县| 卫辉市| 桓仁|