摘要:前言方法是早期提供的一種基于的線程同步方法,本文先介紹相關的數據結構類,然后從方法的內部實現入手,簡單分析相關的原理和實現類用于實現的定待和喚醒,不同平臺操作系統平臺對應的定義在文件類的分配和釋放使用了對象緩存,靜態字段用于緩存當前
前言
Object wait/notify 方法是早期 JVM 提供的一種基于 Object Monitor 的線程同步方法,本文先介紹相關的數據結構(類),然后從 wait/notify 方法的內部實現入手,簡單分析 Object Monitor 相關的原理和實現
ParkPer-thread blocking support for JSR166. Basically, park acts like wait, uppark like notify
Park 類用于實現 JavaThread 的定待(park/wait)和喚醒(unpark/notify),不同平臺(操作系統)
PlatformParkerlinux 平臺對應的 PlatformParker 定義在 hotspot/src/os/linux/vm/os_linux.hpp 文件
class PlatformParker : public CHeapObjallocate & release{ protected: enum { REL_INDEX = 0, ABS_INDEX = 1 }; int _cur_index; // which cond is in use: -1, 0, 1 pthread_mutex_t _mutex[1]; pthread_cond_t _cond[2]; // one for relative times and one for abs. public: // TODO-FIXME: make dtor private ~PlatformParker() { guarantee(0, "invariant"); } public: PlatformParker() { int status; status = pthread_cond_init(&_cond[REL_INDEX], os::Linux::condAttr()); assert_status(status == 0, status, "cond_init rel"); status = pthread_cond_init(&_cond[ABS_INDEX], NULL); assert_status(status == 0, status, "cond_init abs"); status = pthread_mutex_init(_mutex, NULL); assert_status(status == 0, status, "mutex_init"); _cur_index = -1; // mark as unused } };
Parker 類的分配和釋放使用了對象緩存,靜態字段 FreeList 用于緩存當前所有可用的 Parker,ListLock 用于實現對 FreeList 鎖,靜態方法 Allocate 和 Release 用于分配和釋放 Parker
class Parker { ... public: ... static Parker *Allocate(JavaThread *t); static void Release(Parker *e); private: static Parker *volatile FreeList; static volatile int ListLock; }
Allocate 方法首先嘗試從 FreeList 中獲取 Parker,在此之前要先獲取 ListLock;如果分配失敗則嘗試 new 一個新的 parker,最后設置 Parker 的 AssociatedWith 字段將 Parker 和 JavaThread 關聯
Parker * Parker::Allocate (JavaThread * t) { guarantee (t != NULL, "invariant") ; Parker * p ; // Start by trying to recycle an existing but unassociated // Parker from the global free list. // 8028280: using concurrent free list without memory management can leak // pretty badly it turns out. Thread::SpinAcquire(&ListLock, "ParkerFreeListAllocate"); { p = FreeList; if (p != NULL) { FreeList = p->FreeNext; } } Thread::SpinRelease(&ListLock); if (p != NULL) { guarantee (p->AssociatedWith == NULL, "invariant") ; } else { // Do this the hard way -- materialize a new Parker.. p = new Parker() ; } p->AssociatedWith = t ; // Associate p with t p->FreeNext = NULL ; return p ; }park unpark ObjectMonitor ObjectSynchronizer wait
Object 類中的很多方法都是 native 方法,wait 也不例外
public final void wait() throws InterruptedException { wait(0); } public final native void wait(long timeout) throws InterruptedException;
wait 方法對應的 native 函數為 JVM_MonitorWait
JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms)) JVMWrapper("JVM_MonitorWait"); Handle obj(THREAD, JNIHandles::resolve_non_null(handle)); JavaThreadInObjectWaitState jtiows(thread, ms != 0); if (JvmtiExport::should_post_monitor_wait()) { JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms); // The current thread already owns the monitor and it has not yet // been added to the wait queue so the current thread cannot be // made the successor. This means that the JVMTI_EVENT_MONITOR_WAIT // event handler cannot accidentally consume an unpark() meant for // the ParkEvent associated with this ObjectMonitor. } ObjectSynchronizer::wait(obj, ms, CHECK); JVM_END
它首先調用 JNIHandles::resolve_non_null 函數將 jobject 類型的 handle 轉化為 oop(關于 oop 和 Handle 概念可以參考之前的系列文章),然后調用 ObjectSynchronizer 類的靜態方法 wait,這里出現了第一個和 Object Monitor 相關的類 ObjectSynchronizer,先做個標記,接著往下看
int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { if (UseBiasedLocking) { BiasedLocking::revoke_and_rebias(obj, false, THREAD); assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); } if (millis < 0) { TEVENT(wait - throw IAX); THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative"); } ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj(), inflate_cause_wait); DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis); monitor->wait(millis, true, THREAD); // This dummy call is in place to get around dtrace bug 6254741. Once // that"s fixed we can uncomment the following line, remove the call // and change this function back into a "void" func. // DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD); return dtrace_waited_probe(monitor, obj, THREAD); }
這里出現了第二個類 ObjectMonitor(主角),通過 ObjectSynchronizer::inflate 方法獲取對象的 ObjectMonitor 后調用 monitor 的 wait 方法.
總結文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66728.html
摘要:由此可見,自旋鎖和各有優劣,他們分別適用于競爭不多和競爭激烈的場景中。每一個試圖進入同步代碼塊的線程都會被封裝成對象,它們或在對象的中,或在中,等待成為對象的成為的對象即獲取了監視器鎖。 前言 系列文章目錄 前面兩篇文章我們介紹了synchronized同步代碼塊以及wait和notify機制,大致知道了這些關鍵字和方法是干什么的,以及怎么用。 但是,知其然,并不知其所以然。 例如...
摘要:前言網上各路大神總結過各種關于內部實現,看別人的文章總覺得不過癮,所以有了這篇文章,嘗試再扒一次的底褲數據結構在分析源代碼之前需要了解相關概念,比如等,參考網絡上各種解說或者之前系列文章,這里重點介紹一下,,每個在內部都有一個的對象與之對應 前言 網上各路大神總結過各種關于 hotspot jvm synchronized 內部實現,看別人的文章總覺得不過癮,所以有了這篇文章,嘗試再扒...
摘要:準備工作假設源代碼目錄為編譯時啟用了解釋器參考編譯和調試調用棧先在函數參考虛擬機入口中設斷點,然后在的方法中設置斷點通過宏獲取當前,然后創建第個棧幀,然后進入解釋執行字節碼 準備工作 假設 openjdk 源代碼目錄為 jdk9dev 編譯 openjdk 時啟用了 zero 解釋器(參考 OpenJDK9 Hotspot Mac OSX 編譯和調試) 調用棧 先在 JavaMai...
摘要:占用率太高,還出各種奇怪問題,轉投調試安裝下載源代碼漫長等待,中間無數次中斷安裝安裝可選如果要使用解釋器,需要安裝設置調試級別,設成可以提供更多的調試信息設置路徑 Intellij CLion CPU 占用率太高,還出各種奇怪問題,轉投 Xcode 調試 hotspot 安裝 hg # brew install hg 下載 open jdk 9 源代碼 # hg clone http...
摘要:前言語言可以精確控制對象內存分配,出于性能考慮框架系統程序基本都會自己造輪子開發各種內存管理模塊也不例外,它通過和方法的訪問級別以及重載和方法來管理虛擬機內部對象的內存內存管理相關的基類定義了幾個基類來作為大部分對象的基類顧名思義,它們只能 前言 C++ 語言可以精確控制對象內存分配,出于性能考慮 C++ 框架 or 系統程序基本都會自己 造輪子 開發各種內存管理模塊. hotspot...
閱讀 3933·2021-09-22 10:02
閱讀 3365·2019-08-30 15:52
閱讀 3061·2019-08-30 12:51
閱讀 755·2019-08-30 11:08
閱讀 2065·2019-08-29 15:18
閱讀 3106·2019-08-29 12:13
閱讀 3592·2019-08-29 11:29
閱讀 1872·2019-08-29 11:13