锁的消除和粗化

锁的消除

出现的时机:虚拟机即时编译期运行时。

出现的原因:主要判断依据就是来源于逃逸分析的数据支持,如果判断在一段代码中,堆上的所有数据都不会逃逸出去从而被其他线程访问到,那就可以把它们当做栈上的数据对待,认为它们是线程私有,同步锁无须进行。

出现的典型例子:



本身对于String的连接操作JVM会转化成StringBudiler进行连接,既然转化成了sb,那么其实sb是一个局部变量,对于append操作加锁并没有任何效果,因为其他线程在外部是访问不到它的,就可以进行锁的消除。


锁的粗化

原则上对于锁的使用都是需要细化到尽量小的范围,大部分情况下,都是正确的,但是一些列的加锁和解锁操作很是麻烦。造成性能损坏。

所以有了锁的粗化的概念。类似上图中的append方法,如果虚拟机探测到有一串零碎操作都是对同一对象加锁,将会把加锁同步的范围扩展到整个操作序列的外部,也就是在第一个和最后一个append操作之后。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
synchronized和ReentrantLock的性能不能一概而论,因为它们在不同的场景下表现可能会有所不同。早期版本的synchronized在很多场景下性能相差较大,但在后续版本中进行了较多改进,在低竞争场景中可能优于ReentrantLock。JDK6中synchronized加入了自适应自旋、消除粗化、轻量级、偏向等一系列优化,官方也提倡在能满足需求的前提下优先考虑使用synchronized进行同步。[1][2] ReentrantLock是标准的乐观的实现,它通过内部的while循环判断是否被其他线程所持有,当其他线程持有时,就会一直自旋判断是否被释放。如果资源竞争激烈,同时竞争激烈,使用乐观可能会导致很多线程一直在循环等待,当线程数和执行时间达到一个临界值时,乐观的性能可能会比线程挂起的效率更低,循环等待的开销会大于线程挂起的开销。因此,当需要加的代码块执行时间普遍很长时,不建议使用ReentrantLock。[2] 另一方面,当资源竞争激烈,同时尝试获取的线程很多时,部分线程等待过久,如果使用synchronized,会导致慢慢膨胀,资源占有会越来越多。为了保证synchronized的性能,加的代码块需要保证执行时间稳定,不会突然暴增。[2] 总的来说,synchronized和ReentrantLock在不同的场景下可能有不同的性能表现,需要根据具体情况选择合适的机制。synchronized在低竞争场景中可能优于ReentrantLock,而ReentrantLock则提供了更多的便利方法,可以进行精细的同步操作,甚至实现synchronized难以表达的用例。[1][3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值