菲洛嘉青春动能素135HA FILLMED® NCTF 135HA LED指示灯的常见故障分析 智微智能 Elkhartlake K075终端,零售产业新选择 天空蓝拓客管理系统详细介绍版 muso公链项目 天使计划 是什么?[秘] 独家揭秘最前沿的家装“黑科技”——掌赋 天博体育欧洲杯特辑,东道主法兰西的失意2016 亚马逊的送货侦察员 学习听起来像挡泥板 Google Comics Factory使ML变得容易 笑着说-男性或女性 Amazon Rekognition中更好的人脸检测 关于Spaun的真相-大脑模拟 两个聊天机器人彼此聊天-有趣又怪异 GANPaint:将AI用于艺术 WCF和WF给予社区 从耳朵到脸 所有神经网络的深层缺陷 蠕虫在尾巴上平衡杆子 Kickstarter上的OpenCV AI套件 TensorFlow-Google的开源AI和计算引擎 众包取代新闻工作者 Google的DeepMind学会玩街机游戏 哑机器人V智能机器人 .NET与.NET 5融为一体 Google的深度学习-语音识别 LInQer将.NET LINQ移植到Javascript 机器人TED演讲-新的图灵测试? GAN的发明者加入苹果 您的智能手机会监视您键入的内容 人工智能帮助改善国际象棋 Zalando Flair NLP库已更新 TensorFlow 1.5包含移动版本 AlphaGo输了一场比赛-比分3-1 虚拟机器学习峰会 Microsoft开源AI调试工具 SharePoint走向移动 F#4.0发出文化变革的信号 克里斯蒂拍卖AI艺术品 人工智能如何区分 Facebook在蒙特利尔的新AI实验室 Mozilla想要您的声音 微软使用极深的神经网络赢得ImageNet 建立AI合作伙伴关系 .NET Core 3-Microsoft几乎回到了起点 神经网络-更好的销售商? Google使用AI查找您的住所 虹膜-适用于Android的Siri证明苹果没有优势 TensorFlow 2提供更快的模型训练 深度学习研究人员将为Google工作
您的位置:首页 >计算机基础 >

synchronized批量重偏向与批量撤销

synchronized批量重偏向与批量撤销

批量重偏向:如果一个类的大量对象被一个线程T1执行了同步操作,也就是大量对象先偏向了T1,T1同步结束后,另一个线程也将这些对象作为锁对象进行操作,会导偏向锁重偏向的操作。批量撤销:当一个偏向锁如果撤销次数到达40的时候就认为这个对象设计的有问题;那么JVM会把这个对象所对应的类所有的对象都撤销偏向锁;并且新实例化的对象也是不可偏向的。

可以通过命令java -XX:+PrintFlagsFinal -version|grep 'BiasedLocking'来看JVM中的默认配置:

intx BiasedLockingBulkRebiasThreshold= 20{product}intx BiasedLockingBulkRevokeThreshold= 40{product}intx BiasedLockingDecayTime= 25000 {product}intx BiasedLockingStartupDelay = 4000{product}bool TraceBiasedLocking= false {product}bool UseBiasedLocking= true{product}
BiasedLockingBulkRebiasThreshold:偏向锁批量重偏向的默认阀值为20次。BiasedLockingBulkRevokeThreshold:偏向锁批量撤销的默认阀值为40次。BiasedLockingDecayTime:距上次批量重偏向25秒内,撤销计数达到40,就会发生批量撤销。每隔(>=)25秒,会重置在[20, 40)内的计数,这意味着可以发生多次批量重偏向。

批量重偏向(BulkRebias)

测试代码:

package com.morris.concurrent.syn.batch;import org.openjdk.jol.info.ClassLayout;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.LockSupport;public class BulkBias {private static Thread t1, t2;public static void main(String[] args) throws InterruptedException {// 延时产生可偏向对象TimeUnit.SECONDS.sleep(5);List<B> objects = new ArrayList<>(); // 创建50个对象,锁状态为101,匿名偏向锁for (int i = 0; i < 50; i++) {objects.add(new B());}t1 = new Thread(() -> {for (int i = 0; i < objects.size(); i++) {synchronized (objects.get(i)) { // 50个对象全部偏向t1 101}}LockSupport.unpark(t2);});t2 = new Thread(() -> {LockSupport.park();//这里面只循环了30次!!!for (int i = 0; i < 30; i++) {Object a = objects.get(i);synchronized (a) {//分别打印第19次和第20次偏向锁重偏向结果if (i == 18 || i == 19) {System.out.println("第" + (i + 1) + "次偏向结果");System.out.println((ClassLayout.parseInstance(a).toPrintable())); // 第19次轻量级锁00,第20次偏向锁101,偏向t2}}}});t1.start();t2.start();t2.join();System.out.println("打印list中第11个对象的对象头:");System.out.println((ClassLayout.parseInstance(objects.get(10)).toPrintable())); // 01 无锁System.out.println("打印list中第26个对象的对象头:");System.out.println((ClassLayout.parseInstance(objects.get(25)).toPrintable())); // 101 偏向t2System.out.println("打印list中第41个对象的对象头:");System.out.println((ClassLayout.parseInstance(objects.get(40)).toPrintable())); // 101 偏向t1}}class B {}

运行结果如下:

第19次偏向结果com.morris.concurrent.syn.batch.B object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 40 f3 bc 1d (01000000 11110011 10111100 00011101) (498922304)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total第20次偏向结果com.morris.concurrent.syn.batch.B object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 05 69 6c 1e (00000101 01101001 01101100 00011110) (510421253)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total打印list中第11个对象的对象头:com.morris.concurrent.syn.batch.B object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total打印list中第26个对象的对象头:com.morris.concurrent.syn.batch.B object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 05 69 6c 1e (00000101 01101001 01101100 00011110) (510421253)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total打印list中第41个对象的对象头:com.morris.concurrent.syn.batch.B object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 05 60 6c 1e (00000101 01100000 01101100 00011110) (510418949)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

运行结果分析:

当一个线程t1运行结束后,所有的对象都偏向t1。线程t2只对前30个对象进行了同步,0-18的对象会偏向锁(101)升级为轻量级锁(00),19-29的对象由于撤销次数达到20,触发批量重偏向,偏向线程t2。t2结束后,0-18的对象由轻量级锁释放后变成了无锁,19-29的对象偏向t2,30-49的对象还是偏向t1。

总结:批量重偏向会以class为单位,为每个class维护一个偏向锁撤销计数器,每一次该class的对象发生偏向撤销操作时,该计数器+1,当这个值达到重偏向阈值(默认20)时,JVM就认为该class的偏向锁有问题,因此会进行批量重偏向。

批量撤销(BulkRevoke)

测试代码如下:

package com.morris.concurrent.syn.batch;import org.openjdk.jol.info.ClassLayout;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.LockSupport;public class BulkBiasAndRevoke {private static Thread t1, t2, t3, t4;public static void main(String[] args) throws InterruptedException {TimeUnit.SECONDS.sleep(5); // 等待偏向延迟时间到达List<L> list = new ArrayList<>();for (int i = 0; i < 80; i++) {list.add(new L());}t1 = new Thread(() -> {for (int i = 0; i < 60; i++) {L l = list.get(i);synchronized (l) {}}LockSupport.unpark(t2);}, "t1");t2 = new Thread(() -> {LockSupport.park();for (int i = 0; i < 60; i++) {L l = list.get(i);synchronized (l) {}}}, "t2");t3 = new Thread(() -> {LockSupport.park();System.out.println("t3");for (int i = 0; i < 60; i++) {L l = list.get(i);// 0-18 01// 19-59 101 偏向t2synchronized (l) {// 0-59 00}// 0-59 01}}, "t3");t4 = new Thread(() -> {synchronized (list.get(65)) {System.out.println("t4 begin" + ClassLayout.parseInstance(list.get(65)).toPrintable()); // 101LockSupport.unpark(t3);try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t4 end" + ClassLayout.parseInstance(list.get(65)).toPrintable()); // 00System.out.println("t4 end" + ClassLayout.parseInstance(list.get(66)).toPrintable()); // 101}}, "t1");t4.start();t1.start();t2.start();t3.start();t3.join();t4.join();System.out.println(ClassLayout.parseInstance(new L()).toPrintable()); // 01}}class L {}

运行结果如下:

t4 begincom.morris.concurrent.syn.batch.L object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 05 61 79 1e (00000101 01100001 01111001 00011110) (511271173)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes totalt4 endcom.morris.concurrent.syn.batch.L object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 28 ef c2 1d (00101000 11101111 11000010 00011101) (499314472)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes totalt4 endcom.morris.concurrent.syn.batch.L object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes totalcom.morris.concurrent.syn.batch.L object internals: OFFSETSIZE TYPE DESCRIPTION VALUE0 4(object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4(object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4(object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253) 12 4(loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total
t1执行完后,0-59的对象偏向t1。t2执行完后,0-18的对象为无锁,19-59偏向t2。t3执行时由于之前执行过批量重偏向了,所以这里会升级为轻量级锁。t4休眠前对象65为匿名偏向状态,t4休眠后,由于触发了批量撤销,所以锁状态变为轻量级锁,所以批量撤销会把正在执行同步的对象的锁状态由偏向锁变为轻量级锁,而不在执行同步的对象的锁状态不会改变(如对象66)。

总结:批量重偏向和批量撤销是针对类的优化,和对象无关。偏向锁重偏向一次之后不可再次重偏向。当某个类已经触发批量撤销机制后,JVM会默认当前类产生了严重的问题,剥夺了该类的新实例对象使用偏向锁的权利。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。