摘要:源碼實現如下表示是否有異常如果是使用了偏向鎖,要撤銷偏向鎖在中可以看到方法的實現。
wait源碼實現如下
//TRAPS表示是否有異常 void 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"); } ...
在biasedLocking.cpp中可以看到方法的實現。整體結構劃分如下
BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { //1:必須在安全點 assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); //2:讀取對象頭 markOop mark = obj->mark(); if (mark->is_biased_anonymously() && !attempt_rebias) { //3:沒有線程獲取了偏向鎖 } else if (mark->has_bias_pattern()) { //4:已經偏向了 } //5:沒有執行偏向,通過啟發式的方式決定到底是執行撤銷還是執行rebias HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias); if (heuristics == HR_NOT_BIASED) { //5.1:偏向狀態改成了不需要偏向 } else if (heuristics == HR_SINGLE_REVOKE) { //5.2:啟發式決定執行單次的撤銷 } //6:等到虛擬機運行到safepoint,實際就是執行 VM_BulkRevokeBias 的doit的 bulk_revoke_or_rebias_at_safepoint方法 VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD, (heuristics == HR_BULK_REBIAS), attempt_rebias); VMThread::execute(&bulk_revoke); return bulk_revoke.status_code(); }沒有獲取偏向鎖
這里表示還沒有被偏向,并且不是執行rebias
// We are probably trying to revoke the bias of this object due to // an identity hash code computation. Try to revoke the bias // without a safepoint. This is possible if we can successfully // compare-and-exchange an unbiased header into the mark word of // the object, meaning that no other thread has raced to acquire // the bias of the object. markOop biased_value = mark; //prootype本身構建的是 markOop( no_hash_in_place | no_lock_in_place ); markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); //執行CAS,如果當前對象的mark沒有變更,就換成 unbiased_prototype markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark); if (res_mark == biased_value) { //如果之前的和現在的一樣,說明撤銷成功,BIAS_REVOKED本身是一個枚舉 return BIAS_REVOKED; }已經被其它線程獲取了偏向
//已經被線程偏向了,獲取Klass對象,即類本身的頭,obj則是它的實例 Klass* k = Klass::cast(obj->klass()); markOop prototype_header = k->prototype_header(); if (!prototype_header->has_bias_pattern()) { //對象當前的偏向狀態已經過期,并且是不可偏向的,直接設置成已經撤銷偏向即可 // This object has a stale bias from before the bulk revocation // for this data type occurred. It"s pointless to update the // heuristics at this point so simply update the header with a // CAS. If we fail this race, the object"s bias has been revoked // by another thread so we simply return and let the caller deal // with it. markOop biased_value = mark; markOop res_mark = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark); assert(!(*(obj->mark_addr()))->has_bias_pattern(), "even if we raced, should still be revoked"); return BIAS_REVOKED; } else if (prototype_header->bias_epoch() != mark->bias_epoch()) { //實例的epoch和類本身的epoch值不一樣,說明它已經過期,也就是說這個對象當前處于未偏向但是可偏向的狀態(rebiasable) // The epoch of this biasing has expired indicating that the // object is effectively unbiased. Depending on whether we need // to rebias or revoke the bias of this object we can do it // efficiently enough with a CAS that we shouldn"t update the // heuristics. This is normally done in the assembly code but we // can reach this point due to various points in the runtime // needing to revoke biases. if (attempt_rebias) { //執行rebias wait希望直接撤銷 assert(THREAD->is_Java_thread(), ""); markOop biased_value = mark; markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch()); markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark); if (res_mark == biased_value) { //當前線程搶到了這個對象的偏向 return BIAS_REVOKED_AND_REBIASED; } } else { markOop biased_value = mark; markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); //CAS撤銷偏向鎖 markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark); if (res_mark == biased_value) { //撤銷了偏向 return BIAS_REVOKED; } } }啟發式策略
//啟發式的方式決定要做那種操作static HeuristicsResult update_heuristics(oop o, bool allow_rebias) { markOop mark = o->mark(); if (!mark->has_bias_pattern()) { //不可偏向直接返回 return HR_NOT_BIASED; } //控制撤銷的次數 // Heuristics to attempt to throttle the number of revocations. // Stages: // 1. Revoke the biases of all objects in the heap of this type, // but allow rebiasing of those objects if unlocked. // 2. Revoke the biases of all objects in the heap of this type // and don"t allow rebiasing of these objects. Disable // allocation of objects of that type with the bias bit set. Klass* k = o->blueprint(); jlong cur_time = os::javaTimeMillis(); //獲取上次執行bulk revication的時間 jlong last_bulk_revocation_time = k->last_biased_lock_bulk_revocation_time(); //獲取執行bulk revocation的次數 int revocation_count = k->biased_lock_revocation_count(); //定義在globs.hpp,BiasedLockingBulkRebiasThreshold取值為20;BiasedLockingBulkRevokeThreshold取值為40,BiasedLockingDecayTime為25000毫秒 if ((revocation_count >= BiasedLockingBulkRebiasThreshold) && (revocation_count < BiasedLockingBulkRevokeThreshold) && (last_bulk_revocation_time != 0) && (cur_time - last_bulk_revocation_time >= BiasedLockingDecayTime)) { // This is the first revocation we"ve seen in a while of an // object of this type since the last time we performed a bulk // rebiasing operation. The application is allocating objects in // bulk which are biased toward a thread and then handing them // off to another thread. We can cope with this allocation // pattern via the bulk rebiasing mechanism so we reset the // klass"s revocation count rather than allow it to increase // monotonically. If we see the need to perform another bulk // rebias operation later, we will, and if subsequently we see // many more revocation operations in a short period of time we // will completely disable biasing for this type. //在執行了一定時間之內,執行的撤銷次數沒有超過閾值,那么認為可以優先執行bulk rebias,因此將計數回歸原始值 k->set_biased_lock_revocation_count(0); revocation_count = 0; } // Make revocation count saturate just beyond BiasedLockingBulkRevokeThreshold if (revocation_count <= BiasedLockingBulkRevokeThreshold) { //計算執行撤銷的次數 revocation_count = k->atomic_incr_biased_lock_revocation_count(); } if (revocation_count == BiasedLockingBulkRevokeThreshold) { //達到執行bulk revoke的閾值,執行bulk revoke return HR_BULK_REVOKE; } if (revocation_count == BiasedLockingBulkRebiasThreshold) { //達到 bulk rebias的閾值,執行bulk rebias return HR_BULK_REBIAS; } //默認執行單次的撤銷 return HR_SINGLE_REVOKE; }bulk_revoke_or_rebias_at_safepoint
bulk revoke的關鍵在于它會遍歷所有線程棧的每一幀
static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o, bool bulk_rebias, bool attempt_rebias_of_object, JavaThread* requesting_thread) { … if (bulk_rebias) { ... // Now walk all threads" stacks and adjust epochs of any biased // and locked objects of this data type we encounter //遍歷所有的線程 for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) { //遍歷線程棧的每一幀,獲取所有的監視器 GrowableArray* cached_monitor_info = get_or_compute_monitor_info(thr); for (int i = 0; i < cached_monitor_info->length(); i++) { MonitorInfo* mon_info = cached_monitor_info->at(i); oop owner = mon_info->owner(); markOop mark = owner->mark(); if ((owner->klass() == k_o) && mark->has_bias_pattern()) { // We might have encountered this object already in the case of recursive locking assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment"); //更新所有棧中的有偏向鎖的epoch owner->set_mark(mark->set_bias_epoch(cur_epoch)); } } } ... // At this point we"re done. All we have to do is potentially// adjust the header of the given object to revoke its bias. revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread); } … if (attempt_rebias_of_object && o->mark()->has_bias_pattern() && klass->prototype_header()->has_bias_pattern()) { //bias_epoch本身則是表示獲取了偏向鎖 markOop new_mark = markOopDesc::encode(requesting_thread, o->mark()->age(), klass->prototype_header()->bias_epoch()); o->set_mark(new_mark); //執行rebiase status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED; ... } }
revoke_bias的執行如下
static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread) { markOop mark = obj->mark(); … //偏向鎖的頭 markOop biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age); //非偏向鎖的頭 markOop unbiased_prototype = markOopDesc::prototype()->set_age(age); … //獲取偏向的線程 JavaThread* biased_thread = mark->biased_locker(); if (biased_thread == NULL) { // Object is anonymously biased. We can get here if, for // example, we revoke the bias due to an identity hash code // being computed for an object. if (!allow_rebias) { //沒有線程獲取,又需要執行rebias,改掉對象頭即可 obj->set_mark(unbiased_prototype); } ... //撤銷完畢 return BiasedLocking::BIAS_REVOKED; } … //線程活著 //遍歷棧幀,獲取所有這個線程的監視器,按照最年輕到最老的順序 GrowableArray* cached_monitor_info = get_or_compute_monitor_info(biased_thread); BasicLock* highest_lock = NULL; for (int i = 0; i < cached_monitor_info->length(); i++) { MonitorInfo* mon_info = cached_monitor_info->at(i); if (mon_info->owner() == obj) { ... // Assume recursive case and fix up highest lock later //當前棧幀存在了這個對象的鎖 markOop mark = markOopDesc::encode((BasicLock*) NULL); highest_lock = mon_info->lock(); //更新棧中的mark為NULL highest_lock->set_displaced_header(mark); } ... } } if (highest_lock != NULL) { // Fix up highest lock to contain displaced header and point // object at it //將最久的那個lock更新為沒有偏向 ,棧中 設置了鎖記錄 highest_lock->set_displaced_header(unbiased_prototype); // Reset object header to point to displaced mark //將對象頭指向棧中的位置,這樣表示就沒有偏向了 obj->set_mark(markOopDesc::encode(highest_lock)); assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit"); ... } else { ... if (allow_rebias) { obj->set_mark(biased_prototype); } else { // Store the unlocked value into the object"s header. obj->set_mark(unbiased_prototype); } } //撤銷完畢 return BiasedLocking::BIAS_REVOKED; }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72752.html
摘要:關鍵字經過編譯之后,會在同步塊的前后分別形成和這兩個字節碼指令。當我們的把字節碼加載到內存的時候,會對這兩個指令進行解析。這兩個字節碼都需要一個類型的參數來指明要鎖定和解鎖的對象。最后喚醒暫停的線程。 文章簡介 前面我有文章介紹了synchronized的基本原理,這篇文章我會從jvm源碼分析synchronized的實現邏輯,希望讓大家有一個更加深度的認識 內容導航 從synchr...
摘要:實現原理虛擬機鎖原理虛擬機中對象頭部信息可以看見對象頭中結構中的成員,允許壓縮。否則,將偏向鎖撤銷,升級為輕量級鎖。存在明顯多線程競爭的場景下使用偏向鎖是不合適的,例如生產者消費者隊列。 synchronied實現原理 虛擬機鎖原理 虛擬機中對象頭部信息 /*hotspot/src/share/vm/oops/oop.hpp*/ class oopDesc { friend cla...
摘要:線程安全的概念什么時候線程不安全怎樣做到線程安全怎么擴展線程安全的類對線程安全的支持對線程安全支持有哪些中的線程池的使用與中線程池的生命周期與線程中斷中的鎖中常見死鎖與活鎖的實例線程同步機制顯示鎖使用與原理原理剖析原理中的與原理偏向鎖狀態 showImg(https://segmentfault.com/img/bVblUE9?w=1354&h=1660); 線程安全的概念 showI...
摘要:而導致這個問題的原因是線程并行執行操作并不是原子的,存在線程安全問題。表示自旋鎖,由于線程的阻塞和喚醒需要從用戶態轉為核心態,頻繁的阻塞和喚醒對來說性能開銷很大。 文章簡介 synchronized想必大家都不陌生,用來解決線程安全問題的利器。同時也是Java高級程序員面試比較常見的面試題。這篇文正會帶大家徹底了解synchronized的實現。 內容導航 什么時候需要用Synchr...
閱讀 671·2023-04-25 18:59
閱讀 1211·2021-09-22 16:00
閱讀 1889·2021-09-22 15:42
閱讀 3594·2021-09-22 15:27
閱讀 1246·2019-08-30 15:54
閱讀 1104·2019-08-30 11:16
閱讀 2445·2019-08-29 16:24
閱讀 820·2019-08-29 12:14