JVM 基於一種啓發式的做法判斷是否應該觸發批量撤銷或批量重偏向。
依賴三個閾值作出判斷:
# 批量重偏向閾值
-XX:BiasedLockingBulkRebiasThreshold=20
# 重置計數的延遲時間
-XX:BiasedLockingDecayTime=25000
# 批量撤銷閾值
-XX:BiasedLockingBulkRevokeThreshold=40
啓發式的判斷源碼如下:
static HeuristicsResult update_heuristics(oop o, bool allow_rebias) {
markOop mark = o->mark();
// 如果不是偏向模式直接返回
if (!mark->has_bias_pattern()) {
return HR_NOT_BIASED;
}
// 獲取鎖對象的類元數據
Klass* k = o->klass();
// 當前時間
jlong cur_time = os::javaTimeMillis();
// 該類上一次批量重偏向的時間
jlong last_bulk_revocation_time = k->last_biased_lock_bulk_revocation_time();
// 該類單個偏向撤銷的計數
int revocation_count = k->biased_lock_revocation_count();
// 按默認參數來說:
// 如果撤銷計數大於等於 20,且小於 40,
// 且距上次批量撤銷的時間大於等於 25 秒,就會重置計數。
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.
k->set_biased_lock_revocation_count(0);
revocation_count = 0;
}
if (revocation_count <= BiasedLockingBulkRevokeThreshold) {
// 自增計數
revocation_count = k->atomic_incr_biased_lock_revocation_count();
}
// 此時,如果達到批量撤銷閾值,則進行批量撤銷。
if (revocation_count == BiasedLockingBulkRevokeThreshold) {
return HR_BULK_REVOKE;
}
// 此時,如果達到批量重偏向閾值,則進行批量重偏向。
if (revocation_count == BiasedLockingBulkRebiasThreshold) {
return HR_BULK_REBIAS;
}
// 否則,僅進行單個對象的撤銷偏向
return HR_SINGLE_REVOKE;
}
簡單總結,對於一個類,按默認參數來說:
單個偏向撤銷的計數達到 20,就會進行批量重偏向。
距上次批量重偏向 25 秒內,計數達到 40,就會發生批量撤銷。
每隔 (>=) 25 秒,會重置在 [20, 40) 內的計數,這意味着可以發生多次批量重偏向。
注意:對於一個類來說,批量撤銷只能發生一次,因爲批量撤銷後,該類禁用了可偏向屬性,後面該類的對象都是不可偏向的,包括新創建的對象。