天天看點

從Object.wat()方法看JNI及native方法底層調用邏輯

前言

早上debug join方法的時候,其内部調用wait方法,wait是Object中的native方法,但是在ClassLoader類中的findNative中打斷點,不會進去斷點。然後想了一下,是不是因為Object是Bootstrap類加載器加載的原因。

那麼怎麼才能知道native調用的到底是什麼方法呢?在網上搜尋"Java如何檢視native方法的實作",沒有搜到可用的内容。

索性自己去翻一下hostspot jdk的源碼,我下載下傳的是openjdk-8u40-src-b25-10_feb_2015.zip,可以從openjdk官網下載下傳。

舉個例子,比如我要搜尋Object中的wait方法:

1、openjdk目錄結構分析(有助于快速定位源碼位置)

從Object.wat()方法看JNI及native方法底層調用邏輯
從Object.wat()方法看JNI及native方法底層調用邏輯
從Object.wat()方法看JNI及native方法底層調用邏輯
從Object.wat()方法看JNI及native方法底層調用邏輯
從Object.wat()方法看JNI及native方法底層調用邏輯

請原諒我眼花缭亂的框選,打開Object.c看看:

2、初見Object.c

從Object.wat()方法看JNI及native方法底層調用邏輯

 從wait方法入口進去,實作在jvm.cpp中

JDK中用到的jni接口,最終都會在jvm.h檔案中定義,并在jvm.cpp中作為C++實作的入口,也就是說jvm.cpp是Java世界和JVM中C++世界溝通的橋梁。
從Object.wat()方法看JNI及native方法底層調用邏輯

 JVMWrapper("JVM_MonitorWait");這一句是定義了一個宏

從Object.wat()方法看JNI及native方法底層調用邏輯

 看一下270行,我搜了下Histogram的意思,是直方圖,猜測這裡隻是在做JVM統計,或者為了監控而調用的邏輯。這裡先略過。

2.1 使用oop指針指向Java對象

接着看這行:

從Object.wat()方法看JNI及native方法底層調用邏輯

是把目前執行的java類包裝成一個Handle類型,Handle類型,見下圖,将Java對象指派給了一個oop指針類型。

從Object.wat()方法看JNI及native方法底層調用邏輯

2.2 緊接着這行:JvmtiExport::should_post_monitor_wait(),553行

從Object.wat()方法看JNI及native方法底層調用邏輯

should_post_monitor_wait預設false,在jvmtiEventController.cpp中的recompute_enabled方法中會進行設定,搜了下recompute_enabled在jvmtiEventController.cpp有多處調用,從名字上看可能有事件驅動的邏輯,should_post_monitor_wait的值應該也是響應時間設定的。

有哪些事件?導緻wait方法的這個should_post_monitor_wait變量變化的是哪些事件?
在Java中通過JNI接口可以實作Java調用本地方法;通過JVMTI接口可以實作在C++空間調用Java對象的方法。 

 jvmtiEventController.cpp中的recompute_enabled的部分方法體:

從Object.wat()方法看JNI及native方法底層調用邏輯

再看JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);這行。

從Object.wat()方法看JNI及native方法底層調用邏輯

小結:

寫的好亂,很多細節沒怎麼懂,看了if語句塊中的注釋,這段的意思是:目前線程已經擁有螢幕,但是沒被加到等待隊列中,JVMTI_EVENT_MONITOR_WAIT事件沒辦法處理unpark(),意思應該就是沒辦法釋放鎖。

那post_monitor_wait這個意思應該就是推遲螢幕的等待,就是先不釋放鎖。

2.3 接着看ObjectSynchronizer::wait(obj, ms, CHECK);

這個調用的實作在synchronizer.cpp檔案中,

從Object.wat()方法看JNI及native方法底層調用邏輯

1)首先,如果UseBiasedLocking為true,使用偏向鎖

2)如果millis < 0,抛出異常

3)inflate()中是鎖膨脹更新邏輯

4)調用objectMonitor.cpp中的wait方法。wait的大部分邏輯在這裡。可以參見延伸閱讀[1]

總結:

本文通過介紹openjdk底層源碼的目錄結構,wait方法執行涉及到的調用關系。對從Java方法調用到C++代碼調用有一個感性的認識。具體C++代碼邏輯,還需要進一步分析。

延伸閱讀:

[1] JVM源碼分析之Object.wait/notify實作

[2] 并發程式設計的藝術

[3] 源碼分析:Java中的Thread的建立和運作 

關于搜尋技巧:

文章開頭提到,在網上搜尋"Java如何檢視native方法的實作",沒有搜到可用的内容。然後在看源碼的過程中,看到C++代碼裡的這個方法JVMWrapper。不是很明白,就去搜狗微信上搜尋了JVMWrapper。

搜尋到了源碼分析:Java中的Thread的建立和運作 這篇文章。