Java 并发同步原理高级

小夏 科技 更新 2024-01-30

故事人物。

老王 - JVM

Xiao Nan - 线程.

小女孩 - 线程。

房间 - 对象。

在房间的门上 - 防盗锁 - 显示器重量级锁。

房间上门-小楠书包-轻量锁。

在房间的门上 - 刻有小南的名字 - 偏置锁 - 该物体是线程独有的。

批量重新写入 - 一类偏置锁撤销达到 20 阈值 - 批量重新偏置。

无法雕刻名称 - 批量撤销对此类对象的偏差锁定,并将该类设置为无偏差。

小楠想利用这个房间来保证计算不受其他人的干扰(原子性),最初,他在切换上下文时用防盗锁锁住了门。 这样一来,就算他走了,别人也进不了门,他的工作也安全了。

然而,在许多情况下,没有人与他争夺使用房间的权利。 小姑娘想用房间,但是用的时间错开,小楠白天用,小姑娘晚上用。 每次都锁起来太麻烦了,有没有更简单的方法?

萧楠和小姑娘商量了一下,答应不锁门,但谁用了房间,谁把书包挂在门口,可是他们的书包都是一样的款式,所以每次进门前,他们都要翻阅书包,看看课本是谁,是不是自己的, 然后他们就可以进门了,这样一来,这个省就被锁住了,也没上锁了。如果包不是你自己的,那就在门外等着,下次通知对方锁门。

后来,小女孩回到了老家,很长一段时间都不会使用这个房间。 小楠还是每次都挂着书包,翻着书包,虽然比锁门容易,但是他还是觉得麻烦。

于是,萧楠干脆在门上刻上了自己的名字:【萧楠的专属房间,别人不该用],下次你来用房间的时候,只要名字还在,那就说明没有人打扰你,你还是可以放心使用的房间。 如果在此期间有人想使用这个房间,那么用户将删除小楠的名字,并将其升级为书包。

同学们都回老家过节了,小楠膨胀了,在20个房间里刻下了自己的名字,他想进去就进去什么。 后来,他回老家度假,这时小姑娘回来了(她也不得不使用这些房间),结果他不得不把萧南可的名字一一抹掉,升级为挂书包的方式。 老王觉得成本有点高,提出了批量重刻的方法,他让小女孩不用挂书包,可以直接在门上刻上自己的名字。

后来,刻名字的现象越来越频繁,老王也受不了了:算了,这些房间是不能刻的,只能挂书包---设置了这种不偏不倚。

它反映在节代码指令中。

轻量级锁的用例:如果一个对象有多个线程需要锁定,但锁定时间是错开的(即没有争用),则可以使用轻量级锁进行优化。

如果有竞争,轻量级锁升级为重量级锁。

轻量级锁对消费者是透明的,即语法保持不变synchronized

假设有两种方法可以同步块,锁定同一个对象。

static final object obj = new object();public static void method1() public static void method2()
创建一个锁记录对象,每个线程的栈帧都会包含一个锁记录结构,可以存储锁对象的标记字

让锁记录中的对象引用指向锁对象,并尝试将对象的标记字替换为 cas(比较和交换、原子性),并将标记字的值保存在锁记录中。

如果 CAS(比较和交换)替换成功,则对象将存储在标头中锁记录地址和状态 00,表示线程已锁定对象,如下所示。

如果 CAS(比较和交换)失败,有两种情况。

如果另一个线程已在对象上持有轻量级锁,则表示存在争用,并且锁扩展过程开始。

如果你自己做同步锁重入器,然后添加锁定记录作为重入计数,如示例中所示。

退出同步块时(解锁时),如果存在值为 null 的锁定记录,则表示存在 reentriency,然后重置锁定记录,这意味着 reentrancy count 为负 1(锁定重入者数)。

退出同步块时(解锁时),锁定记录的值不为空,则使用 CAS(比较和交换、原子性)将标记字的值恢复到对象标头。

如果成功,则解锁将成功。

如果失败,则轻量级锁已充气或升级为重量级锁,并且重量级锁的解锁过程已经开始。

如果 CAS 操作在尝试添加轻量级锁时失败,则另一个线程会向对象添加轻量级锁(存在争用),并且需要锁扩展才能将轻量级锁转换为重量级锁。

static object obj = new object();public static void method1()
当 thread-1 执行轻量级锁时,thread-0 已对对象具有轻量级锁。

此时,thread-1 和轻量级锁失败,进入锁扩容过程。

即为对象对象申请一个监视器锁,让对象指向重量级锁地址。

然后进入监视器的进入列表,自己被阻止

当 thread-0 退出同步块解锁时,使用 cas 将标记字的值恢复到对象标头失败。 这时会进入重量级的解锁过程,即根据监控地址找到监控对象,将 owner 设置为 null,唤醒 entrylist 中阻塞的线程。

Spin 还可用于优化重量级锁何时处于争用状态,以便如果当前线程成功旋转(即,保持锁的线程已退出同步块并释放锁),则当前线程可以避免阻塞。

旋转重试成功的条件。

线程 2 旋转重试 3 次以成功锁定,以免被阻塞。

旋转重试失败的情况。

线程 2 一直在旋转,最终被阻塞。

旋转占用 CPU 时间,单核 CPU 旋转是浪费,多核 CPU 旋转是优势。

在 J**A 6 之后,自旋锁是自适应的,例如,如果对象刚刚在一次自旋操作中成功,那么它认为自旋成功的概率会很高,所以它多旋转几次;相反,旋转更少甚至没有旋转,总之,它更聪明。

j**a 7 之后,您将无法控制是否打开旋转功能。

轻量级锁仍然需要执行 CAS 操作,每次在没有争用的情况下(在其自己的线程中)重新进入锁。

在 J**A 6 中,引入了偏置锁定进行进一步优化:只有第一次使用 CAS 将线程 ID 设置为对象的标记字头,然后发现线程 ID 是你自己的,就意味着没有争用,也不需要重新 CAS。 将来,只要没有竞争,对象就归线程所有。

例如:

static final object obj = new object();public static void m1() public static void m2() public static void m3()

调用对象标头格式。

|--mark word (64 bits) |state | unused:25 | hashcode:31 | unused:1 | age:4 | biased_lock:0 | 01 | normal |正常 |- 偏置锁 | thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | 01 | biased | ptr_to_lock_record:62 | 00 | lightweight locked |轻量级 |- 重量级 | ptr_to_he**yweight_monitor:62 | 10 | he**yweight locked | 11 | marked for gc |
创建对象时:

如果启用了偏置锁定(默认启用),则在创建对象后,标记字值为 0x05,即最后 3 位为 101,其线程、纪元和年龄均为 0

偏置锁默认是延时的,程序启动时不会立即生效,休眠4s后可以勾选,如果想避免延时,可以添加vm参数-xx:biasedlockingstartupdelay=0以禁用延迟。

如果未启用偏置锁,则在创建对象后,标记字值为0x01,即最后 3 位为 001,则其哈希码和年龄为 0,首次使用哈希码时会赋值。

class dog {}
利用 JOL 第三方工具查看对象标头信息。

POM 文件。

org.openjdk.jol jol-core 0.10
注意这个小节的**来理解它,机器没有运行成功,只是注意输出

添加 VM 参数 -xx:biasedlockingstartupdelay=0 public static void main(string args) throws ioexception logdebug("同步"); system.out.println(classlayout.toprintable***true));"t1").start();
输出。

11:08:58.117 c.testbiased[t1] -同步 11:0 00000101 8:58121 c.testbiased [t1] -synchronized 00000000 00000000 00000000 000000000 00000000 00011111 11101011 110100000 00000101与上面输出的差异,查看 11:08:58121 c.testbiased [t1] - 在 00000000 00000000 0000000 0000000 00011111 11101011 11010000 00000101处于偏置锁中后同步,除非有新的争用,否则线程 ID 保持不变
注意当处于偏置锁中的对象被解锁时,线程 ID 仍存储在对象标头中。

在测试运行时上方添加 VM 参数-xx:-usebiasedlocking禁用偏置锁定。

输出。

11:13:10.018 c.testbiased [t1] -同步了第一个 00000000 000000000 000000000 0000000000 0000000000 00000000000 0000000000 00000001 三个日志的最后三位数字不是 101 11:13:10021 c.testbiased[t1] -在 00000000 000000000 00000000 00000000 0000000 001000000 00010100 11110011 10001000 中同步 轻量级锁 11:13:10021 c.testbiased [t1] -synchronized 0000000000 0000000000 000000000000 00 00 00000001 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
4) 测试哈希码并添加 VM 参数-xx:biasedlockingstartupdelay=0以禁用延迟。

正常状态对象开始时没有哈希码,并在第一次调用时生成。

调用哈希码会导致偏置锁被禁用。 因为如果处于偏锁状态,线程id已经存储好了,然后又存储了哈希码,空间不够,所以无法存储。 所以此时状态会变为正常状态。 此外,轻量级锁的哈希码存储在堆栈帧的锁记录中,重量级锁的哈希码存储在监控对象中,解锁时会恢复。

调用对象的哈希码,但线程 ID 存储在偏锁对象的标记字中,如果调用了哈希码,则偏置锁将被撤销。

轻量级锁在锁记录中记录哈希码

重量级锁在监视器中记录哈希码

调用哈希码后使用偏置锁,记得删除它们-xx:-usebiasedlocking

输出。

11:22:10.386 c.testbiased [main] - 调用哈希代码:1778535015 11:22:10391 c.testbiased [t1] -同步前端 00000000 00000000 00000000 01101010 00000010 01001010 01100111 00000001 11:22:10393 c.testbiased[t1] -同步 00000000 000000000 000000000 000000000 001000000 11000011 11110011 01101000 11:22:10393 c.testbiased [t1] -在 00000000 00000000 00000000 01101010 00000010 01001010 01100111 00000001后同步
当其他线程使用偏置锁对象时,偏置锁将升级为轻量级锁。

private static void test2() 抛出 interruptedException 锁当前类对象同步 (testbiased.)。类)如果不使用 wait notify 来使用 join,则必须打开以下注释,因为:t1 线程无法结束,否则底层线程可能会被 jvm 作为 t2 线程复用,并且底层线程 id 相同 *try catch (ioexception e) * },"t1"); t1.start();thread t2 = new thread(()catch (interruptedexception e) log.debug(classlayout.parseinstance(d).toprintable***true));synchronized (d) log.debug(classlayout.parseinstance(d).toprintable***true));"t2"); t2.start();
输出。

[t1] -000000000 00000000 00000000 00000000 00011111 01000001 00010000 00000101处于偏置锁定状态 [t2] -0000000000 000000000 00000000 00011111 01000001 00010000 00000101 T2 线程未锁定且 T1 一致 [T2] -00000 00000 00000000 000000000 00000000 00011111 10110101 11110000 010000000 在轻量级锁 [t2] -0000000000 00000000 0000000000 000000000000 0000000000 解锁后00000001是无偏的
在这种情况下,偏置锁也会被撤销。 因为等待通知仅适用于重量级锁。 偏置锁或轻量级锁升级为重量级锁。

public static void main(string args) throws interruptedexception catch (interruptedexception e) log.debug(classlayout.parseinstance(d).toprintable***true));"t1"); t1.start();new thread(()catch (interruptedexception e) synchronized (d) "t2").start();
输出。

[t1] -0000000000 000000000 000000000 000000000 000000000 000000000 000000000 00000101 偏置锁定 [t1] -000000000 000000000 00000000 00011111 10110011 11111000 00000101锁 [t2] -notify [t1] - 00000000 00000000 00000000 00000000 00011100 11010100 00001101 11001010重量级锁
如果一个对象被多个线程访问,但没有竞争,则偏向线程 t1 的对象仍有机会重新偏向到 t2,这将重置对象的线程 ID

当吊销偏置锁定阈值超过 20 次时,JVM 会认为我是否偏错了,并在锁定这些对象时重新偏向锁定的线程。

private static void test3() throws interruptedexception }synchronized (list) "t1"); t1.start();thread t2 = new thread(()catch (interruptedexception e) log.debug("***"); for (int i = 0; i < 30; i++)log.debug(i + "\t" + classlayout.parseinstance(d).toprintable***true));"t2"); t2.start();
输出。

[t1] -0 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 //- 偏置锁 |t1] -1 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -2 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -3 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -4 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -5 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -6 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -7 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -8 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -9 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -10 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -11 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -12 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -13 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -14 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -15 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -16 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -17 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -18 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -19 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -20 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -21 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -22 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -23 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -24 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -25 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -26 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -27 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -28 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t1] -29 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -t2] -0 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 //偏置到 T1 锁定 [t2] -0 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 //撤销偏置锁,升级到轻量级锁 [.]t2] -0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 //在非偏置锁定中,也就是说,正常状态 [t2] -1 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -1 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -2 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -2 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -2 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -3 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -3 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -3 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -4 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -4 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -4 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -5 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -5 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -5 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -6 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -6 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -6 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -7 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -7 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -7 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -8 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -8 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -9 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -9 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -9 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -10 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -10 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -10 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -11 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -11 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -11 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -12 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -12 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -12 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -13 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -13 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -13 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -14 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -14 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -14 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -15 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -15 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -15 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -16 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -16 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -16 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -17 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -17 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -17 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -18 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -18 00000000 00000000 00000000 00000000 00100000 01011000 11110111 00000000 [t2] -18 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 [t2] -19 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 //第 20 个对象开始,所有这些都处于偏向 t2 的偏置锁中 [t2] -19 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 //批量复偏置,后者都是偏向 t2 的偏置锁t2] -19 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -20 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -20 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -20 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -21 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -21 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -21 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -22 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -22 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -22 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -23 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -23 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -23 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -24 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -24 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -24 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -25 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -25 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -25 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -26 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -26 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -26 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -27 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -27 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -27 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -28 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -28 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -28 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -29 00000000 00000000 00000000 00000000 00011111 11110011 11100000 00000101 [t2] -29 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101 [t2] -29 00000000 00000000 00000000 00000000 00011111 11110011 11110001 00000101
当吊销偏置锁定阈值超过 40 倍时,JVM 认为它确实存在偏置,根本不应该偏置。 因此,整个类中的所有对象都变得无偏,并且新创建的对象也是无偏的。

这里就不打印日志了,你可以自己想想。

static thread t1,t2,t3; private static void test4() throws interruptedexception }locksupport.unpark(t2); "t1"); t1.start();t2 = new thread(()log.debug(i + "\t" + classlayout.parseinstance(d).toprintable***true));locksupport.unpark(t3); "t2"); t2.start();t3 = new thread(()log.debug(i + "\t" + classlayout.parseinstance(d).toprintable***true));"t3"); t3.start();t3.join();log.debug(classlayout.parseinstance(new dog())toprintable***true));
@fork(1) @benchmarkmode(mode.**eragetime) @warmup(iterations=3) @measurement(iterations=5) @outputtimeunit(timeunit.nanoseconds) public class mybenchmark @benchmark public void b() throws exception }
j**a -jar benchmarks.jar

benchmark mode samples score score error units c.i.mybenchmark.a **gt 5 1.542 0.056 ns/op c.i.mybenchmark.b **gt 5 1.518 0.091 ns/op
B有一个锁定的操作,那么为什么它与A和B所花费的时间几乎不同呢?因为 J**A 中有一个 JIT(just-in-time 编译器),它会优化 **的重复执行,而 B 中的 O 对象根本不会被共享,所以在 B 中同步是没有意义的,所以 J**A 会去掉锁。 这个还有一个开关,这个开关默认是开着的,下面的演示会把这个开关关掉。

j**a -xx:-eliminatelocks -jar benchmarks.jar

benchmark mode samples score score error units c.i.mybenchmark.a **gt 5 1.507 0.108 ns/op c.i.mybenchmark.b **gt 5 16.976 1.572 ns/op
您可以看到所需的时间存在显着差异。

多次锁定同一对象,导致线程多次重入,可以使用锁粗化进行优化,这与之前细分锁的粒度不同。

作者:|老城区清道夫|

*:cnblogs.com/xiaoyh/p/17157540.html

相似文章

    Java 并行编程 fork Join 框架解释

    image.PNG分而治之算法是一种解决问题的策略,它将一个复杂的问题分解成几个较小的 相似的子问题,递归地求解这些子问题,然后将这些子问题的解合并,得到原来问题的解。分而治之算法的步骤通常由三个主要部分组成 分 将原始问题分解为一系列子问题。这些子问题应该更小,更容易解决原始问题的版本。征服 递归...

    使用 Java 解析和转换 OpenSSH 和 PuTTY 私钥格式

    两种常用的 SSH 密钥格式及其转换方式。Secure Shell SSH 是一种建立在应用层和传输层之上的安全协议,由 IETF 的网络工作组开发。SSH 是当今最可靠的协议,可为 telnet 会话和其他网络服务提供安全性。SSH协议可以有效防止远程管理过程中的信息泄露。除了用户名和密码的密码认...

    采访中询问如何解决高并发问题

    在互联网行业,高并发是一个共同而严峻的挑战。当系统暴露于大规模用户访问时,可能会导致系统性能下降 响应时间延长,甚至系统崩溃。因此,解决高并发问题对于保证系统的稳定性和用户体验非常重要。本文将从架构层面 数据库层面 缓存技术 优化等不同角度详细介绍高并发场景。.解决架构层面的高并发问题。. 横向扩展...

    参考 java 中 void 的用法

    在 J A 编程语言中,void 是一个特殊关键字,用于指示方法没有返回值。此关键字在定义方法时使用,指示该方法不向调用方返回任何值。在方法主体中,可以调用其他方法并执行各种操作,但最终它们不会返回任何结果。下面是使用 void 关键字的示例 j a复制 在此示例中,我们定义了一个名为sayhell...

    在 Java 中实现 HTTPS 连接的最佳实践

    大家好!我是小黑。今天,我们来谈谈一个热门而实用的话题 如何在j a中实现https连接。在当今的网络世界中,安全性是每个人关注的一大问题,尤其是对于我们程序员而言。想想看,如果你的 或应用程序数据被泄露,那一定有多严重!因此,了解和实现HTTPS连接以保护我们的数据安全是极其重要的。首先,我们必须...