JAVA锁的优化

在前几天的文章:浅谈Java中的锁:Synchronized、重入锁、读写锁 中我们学习了多线程环境下为了保证线程安全需要加各种各样的锁,但是加锁势必会带来性能的损耗,此篇文章就讨论一下如何优化加锁后的程序

锁优化策略

  • 1. 减少锁持有时间

对一个方法加锁,不如只对需要同步的那几行代码加锁,减少线程持有锁的时间。

  • 2. 减小锁粒度

将大对象,拆成小对象进行加锁。例如ConcurrentHashMap采取对segment加锁而不是对整个map加锁,这样只要修改的segment不同,就可以并发的进行。

  • 3. 锁分离

使用我们文章开头提到的文章中所说的读写分离锁或者根据不同的功能进行加锁

  • 4. 锁粗化

策略1要求每个线程持有锁的时间越短越好,但是呢,锁的申请、同步和释放也是需要时间的,所以说如果有频繁的加锁请求时(例如在循环内加锁),最好把多个加锁的请求合并为一个(在循环外加锁),以减少锁的请求及释放的时间。

虚拟机对锁优化做的努力

  • 1. 锁偏向

当一个线程获得锁之后,锁就会进入偏向模式。接下来这个线程如果再次请求锁的时候就不需要再做同步操作了。(即:持有该锁的线程在接下来的执行中遇到同步块时不再需要lock和unlock了,直接执行即可)直到另外的线程前来请求的时候锁偏向才会失效。

锁偏向的优化适用于锁竞争不是很强的场景,如果是竞争激烈的场景则偏向锁会一直处于失效状态。

  • 2. 轻量级锁

如果偏向锁失败,那么系统会进行轻量级锁的操作,使用CAS操作来尝试加锁。如果轻量级锁失败,才调用系统级别的重量级锁(syncrhoized)来加锁。

  • 3. 自旋锁

为了避免使用重量级锁的巨大消耗,虚拟机在轻量级锁失败膨胀后让当前线程做几个空循环(这就是自旋的来源)来赌这个线程可以在自旋之后获得锁,如果还不能获得锁的话则真实的使用重量级锁了。

  • 4. 锁消除

虚拟机在编译时,会对上下文进行扫描,去除那些不可能存在竞争的锁。

总结

为了尽量避免使用重量级锁,JVM首先在编译期先消除一些不可能存在竞争的锁。当一个线程获得锁后会对这个线程偏向以保证此线程再次获得锁时可以减少同步所需的时间。偏向锁失败后会尝试轻量级锁,轻量级锁尝试使用CAS操作来获得锁。如果轻量级锁失败,JVM同样会赌一下此线程很可能很快获得锁,就会尝试自旋锁,将线程做几个空循环。如果自旋锁也失败,那么就只能升级成重量级锁了。


针对于上面所涉及到的知识点我总结出了有1到5年开发经验的程序员在面试中涉及到的绝大部分架构面试题及答案做成了文档和架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习,也可以关注我一下以后会有更多干货分享。

资料获取方式: QQ群搜索“708-701-457” 即可免费领取



猜你喜欢

转载自blog.csdn.net/qq_42982923/article/details/89246980