當(dāng)前位置:首頁 > 公眾號(hào)精選 > 程序喵大人
[導(dǎo)讀]目錄Java線程與OS線程的區(qū)別與關(guān)聯(lián)JNI的作用JNIEnv和JavaVM是啥JNI中數(shù)據(jù)是如何傳遞的Java線程與Native(OS)線程的區(qū)別聯(lián)系:Java線程其實(shí)是一層OS線程的封裝,本質(zhì)上就是OS線程?!疽郧鞍姹镜腏ava線程不是OS線程,是JVM構(gòu)造的用戶態(tài)線程(Gr...


目錄


  • Java線程與OS線程的區(qū)別與關(guān)聯(lián)

  • JNI的作用

  • JNIEnv和JavaVM是啥

  • JNI中數(shù)據(jù)是如何傳遞的




Java線程與Native(OS)線程的區(qū)別



聯(lián)系:Java線程其實(shí)是一層OS線程的封裝,本質(zhì)上就是OS線程?!疽郧鞍姹镜腏ava線程不是OS線程,是JVM構(gòu)造的用戶態(tài)線程(Green Thread),不能充分利用CPU,后期已經(jīng)更改為使用OS線程實(shí)現(xiàn)。】【參考https://mp.weixin.qq.com/s/Gxqnf5vjyaI8eSYejm7zeQ】


區(qū)別:

Java線程可以直接拿到JNIEnv,OS線程需要先attach到JVM,才可以拿到JNIEnv?!緜€(gè)人理解區(qū)別在于是否attach了JVM】

jint AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args);

Java線程可以FindClass成功,OS線程則FindClass失敗,原因是兩者的ClassLoader不同,OS線程AttachCurrentThread后持有的ClassLoader是系統(tǒng)的ClassLoader,如果想要FindClass成功,需要在JNI_Onload時(shí)獲取一份當(dāng)前庫的ClassLoader保存起來,下次FindClass時(shí)使用此ClassLoader去操作。


static?jobject?g_class_loader?=?NULL;

static jmethodID g_find_class_method = NULL;

void?on_load()?{

????JNIEnv?*env?=?get_jni_env();

if (!env) {

return;

}

????jclass?capture_class?=?(*env)->FindClass(env,?"com/captureandroid/BMMCaptureEngine");

jclass class_class = (*env)->GetObjectClass(env, capture_class);

jclass class_loader_class = (*env)->FindClass(env, "java/lang/ClassLoader");

jmethodID class_loader_mid = (*env)->GetMethodID(env, class_class, "getClassLoader", "()Ljava/lang/ClassLoader;");

jobject local_class_loader = (*env)->CallObjectMethod(env, capture_class, class_loader_mid);

g_class_loader = (*env)->NewGlobalRef(env, local_class_loader);

g_find_class_method =

(*env)->GetMethodID(env, class_loader_class, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");

}


jclass?find_class(const?char?*name)?{

JNIEnv *env = bmm_util_get_jni_env();

if (!env) {

return NULL;

}

jclass ret = (*env)->FindClass(env, name);

jthrowable exception = (*env)->ExceptionOccurred(env);

if (exception) {

(*env)->ExceptionClear(env);

jstring name_str = (*env)->NewStringUTF(env, name);

ret = (jclass)(*env)->CallObjectMethod(env, g_class_loader, g_find_class_method, name_str);

(*env)->DeleteLocalRef(env, name_str);

}

return ret;

}




JNI的作用



貼出別人翻譯的【官方文檔https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html#wp16696】的一段話:


JNI最重要的設(shè)計(jì)目標(biāo)就是在不同操作系統(tǒng)上的JVM之間提供二進(jìn)制兼容,做到一個(gè)本地庫不需要重新編譯就可以運(yùn)行不同的系統(tǒng)的JVM上面。為了達(dá)到這一點(diǎn)兒,JNI設(shè)計(jì)時(shí)不能關(guān)心JVM的內(nèi)部實(shí)現(xiàn),因?yàn)镴VM的內(nèi)部實(shí)現(xiàn)機(jī)制在不斷地變,而我們必須保持JNI接口的穩(wěn)定。JNI的第二個(gè)設(shè)計(jì)目標(biāo)就是高效。我們可能會(huì)看到,有時(shí)為了滿足第一個(gè)目標(biāo),可能需要犧牲一點(diǎn)兒效率,因此,我們需要在平臺(tái)無關(guān)和效率之間做一些選擇。最后,JNI必須是一個(gè)完整的體系。它必須提供足夠多的JVM功能讓本地程序完成一些有用的任務(wù)。JNI不能只針對一款特定的JVM,而是要提供一系列標(biāo)準(zhǔn)的接口讓程序員可以把他們的本地代碼庫加載到不同的JVM中去。有時(shí),調(diào)用特定JVM下實(shí)現(xiàn)的接口可以提供效率,但更多的情況下,我們需要用更通用的接口來解決問題。



JNIEnv和JavaVM



就是個(gè)函數(shù)指針。


下圖是JNIEnv的指針結(jié)構(gòu):

JNIEnv其實(shí)是一個(gè)指向本地線程數(shù)據(jù)的接口指針,指針里面包含指向函數(shù)接口的指針,每一個(gè)接口函數(shù)在這表中都有一個(gè)預(yù)定義的偏移位置,類似C 虛函數(shù)表。


代碼如下:

typedef const struct JNINativeInterface *JNIEnv;


struct JNINativeInterface {

void* reserved0;

void* reserved1;

void* reserved2;

void* reserved3;


jint (*GetVersion)(JNIEnv *);


jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,

jsize);

jclass (*FindClass)(JNIEnv*, const char*);

jobject (*AllocObject)(JNIEnv*, jclass);

jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...);

jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);

jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, const jvalue*);

...

};

JavaVM類似

struct JNIInvokeInterface {

void* reserved0;

void* reserved1;

void* reserved2;


jint (*DestroyJavaVM)(JavaVM*);

jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);

jint (*DetachCurrentThread)(JavaVM*);

jint (*GetEnv)(JavaVM*, void**, jint);

jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);

};


typedef const struct JNIInvokeInterface* JavaVM;

知識(shí)點(diǎn)1:為什么使用函數(shù)表而不是寫死某些函數(shù)項(xiàng)?


可將JNI命名空間與本地代碼分離,一個(gè)虛擬機(jī)可以提供多個(gè)版本的JNI函數(shù)表,用于不同場景。例如,虛擬機(jī)可支持兩種JNI函數(shù)表:


  • 一個(gè)用于調(diào)試,做較多的錯(cuò)誤檢查。

  • 一個(gè)用于發(fā)布,做較少的錯(cuò)誤檢查,更高效。


知識(shí)點(diǎn)2:JNIEnv是thread-local,只在當(dāng)前線程有效,Native方法不能將JNIenv從當(dāng)前線程傳遞到另一個(gè)線程。不能跨線程使用JNIEnv【至于JNIEnv為什么設(shè)計(jì)成thread-local,沒搞明白】。


知識(shí)點(diǎn)3:線程間雖然不共享JNIEnv,但是共享JavaVM,然后可以通過GetEnv獲取到當(dāng)前線程的JNIEnv。

jint GetEnv(JavaVM *vm, void **env, jint version);

知識(shí)點(diǎn)4:Native方法接收J(rèn)NI接口指針作為參數(shù)。虛擬機(jī)保證在同一個(gè)線程傳入Native方法的是相同的JNIEnv。如果不同線程調(diào)用Native方法,傳入他們的JNIEnv不同。但JNIEnv間接指向的函數(shù)表在多個(gè)線程間是共享的。


知識(shí)點(diǎn)5:為什么在C語言中調(diào)用Native方法需要將JNIEnv當(dāng)作參數(shù)傳遞,而C 中卻不需要?

// C語言

jstring model_path = (*env)->NewStringUTF(env, path);

// C

jstring model_path = env->NewStringUTF(path);前面列出的JNIEnv是C語言形式,Java還單獨(dú)為C 封裝了一層JNIEnv,簡化版代碼:

struct _JNIEnv {

/* do not rename this; it does not seem to be entirely opaque */

const struct JNINativeInterface* functions;


#if defined(__cplusplus)


jint GetVersion()

{ return functions->GetVersion(this); }


jclass FindClass(const char* name)

{ return functions->FindClass(this, name); }

#endif

}其實(shí)本質(zhì)上還是調(diào)用的C語言那種形式的接口。



JNI中數(shù)據(jù)如何傳遞



這里不詳細(xì)介紹了,大體就是int,float這種基本類型采用拷貝,對象和byte數(shù)組等使用引用形式,所以其實(shí)Java層的byte字節(jié)流數(shù)據(jù)傳到Native層基本不耗時(shí),不會(huì)發(fā)生拷貝【但是Native層如果想使用持有這塊數(shù)據(jù),那就得自己拷貝一份了】。


還有些GlobalReference、LocalReference以及為什么要Delete LocalReference的這類知識(shí)點(diǎn),這些比較基礎(chǔ),就不介紹了,估計(jì)大家也都懂。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉