网站首页 > java教程 正文
互斥锁的系统开销
前文《Java面试必考问题:如何理解关键字synchronized 》我们介绍了 synchronized 关键字给对象加锁是互斥锁,用来实现线程同步。互斥同步对性能最大的影响是线程阻塞,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统性能带来了很大压力。
互斥同步会有两次线程上下文切换的成本:
- 当线程加锁失败时,内核会把线程的状态从 “运行” 状态设置为 “睡眠” 状态,然后把 CPU 切换给其他线程运行;
- 当锁被释放时,之前 “睡眠” 状态的线程会变为 “就绪” 状态,然后内核会在合适的时间,把 CPU 切换给该线程运行。
上下文切换需要几十纳秒到几微秒之间,如果锁住的代码执行时间极短,那花在两次上下文切换的时间就会远多于锁住代码的执行时长。
不做线程切换的自旋锁
虚拟机的开发团队也注意到在很多应用中,共享数据的锁定状态通常只会持续很短的一段时间,为了这么短的时间去挂起和恢复线程很不值得。于是他们想到了一种降低线程切换的系统开销的办法。
在多核处理器的系统中,可以让后面请求锁的那个线程先等一下,暂不需要放弃CPU的执行时间,看当前持有锁的线程是否会很快释放掉。如果等一会就能获得锁,就避免了线程切换的开销了。
为了让后面的线程等待,我们只需让线程执行一个忙循环(busy loop),即所谓的自旋锁(spin lock)。自旋锁是一种比较简单的锁,一直自旋,利用 CPU 周期,直到锁可用为止,是通过自旋操作减少CPU切换以及恢复现场导致的消耗。
自旋锁在JDK 1.4.2中就已经引入,只不过默认是关闭的,可以使用 -XX:+UseSpinning 参数来开启,在JDK 1.6中就已经改为默认开启了。
自旋等待本身虽然避免了线程切换的开销,但它还是要占用处理器时间的,因此,如果锁被占用的时间很短,自旋等待的效果就会非常好,反之,如果锁被占用的时间很长,那么自旋的线程只会白白消耗处理器资源,反而会带来性能上的浪费。因此,自旋等待的时间必须要有一定的限度。
如果自旋超过了限定的次数仍然没有成功获得锁,就应当挂起线程了。自旋次数的默认值是10次,用户可以使用参数 -XX:PreBlockSpin 来更改。
另外注意的是:在单核 CPU 上,自旋锁是无法使用的,因为一个自旋的线程永远不会放弃 CPU。其他占用锁的线程也没有机会执行代码去释放锁。
自适应的自旋锁
在JDK 1.6中引入了自适应的自旋锁。自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。
如果虚拟机认为自旋很有可能成功获得锁,那么它将允许自旋等待持续相对更长的时间。如果对于某个锁,自旋很少成功获得过,那么虚拟机就可能直接省略掉自旋过程,以避免浪费处理器资源。
有了自适应自旋,随着程序运行和性能监控信息的不断完善,虚拟机对程序锁的状况预测就会越来越准确,性能就会越来越好。
我会持续更新关于物联网、云原生以及数字科技方面的文章,用简单的语言描述复杂的技术,也会偶尔发表一下对IT产业的看法,欢迎大家关注,谢谢。
参考资料:《深入理解Java虚拟机:JVM高级特性与最佳实践》
我会持续更新关于物联网、云原生以及数字科技方面的文章,用简单的语言描述复杂的技术,也会偶尔发表一下对IT产业的看法,欢迎大家关注,谢谢。
猜你喜欢
- 2025-06-23 Java阻塞队列:LinkedTransferQueue
- 2025-06-23 Java面试题-锁的膨胀升级过程(锁的机制升降级)
- 2025-06-23 Java中CurrentHashMap的使用原理?
- 2025-06-23 Java并发锁机制和Atomic原理解析(java并发的时候常用的处理方式)
- 2025-06-23 「Java多线程」内置锁(Synchronized)的前世今生
- 2025-06-23 Java 面试题:乐观锁和悲观锁的理解及如何实现,有哪些实现方式?
- 2025-06-23 万字详文:腾讯高可用、高性能 ZooKeeper 源码和实践揭秘
- 2025-06-23 ReentrantLock源码解析:ReentrantLock 的实现原理与 AQS 机制
- 2025-06-23 Java面试题整理:紧跟2025年面试趋势
- 2025-06-23 面试官:说一下 synchronized 锁机制原理 与 Lock 锁机制
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)