【浅谈Java】主要针对Java开发技术知识的讲解。不会大而全详细讲解某一技术知识,只在短暂无事的时刻让你学习或温习Java知识体系中的一叶飘零。
相关文档传送门:
「浅谈Java」三,关键字synchronized同步机制-基础篇「浅淡Java」四,synchronized的锁优化和升级「浅谈Java」五,synchronized中锁的获取和释放何谓自旋锁?
就是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,为了不让线程立刻进入挂起或睡眠状态,而采用循环去检测锁是否被释放,获取锁的过程。
为什么要使用自旋锁
线程的阻塞和唤醒需要CPU从用户态转为核心态,频繁的阻塞和唤醒对CPU来说是一件负担很重的工作。给系统的并发性能带来很大的压力。实际中许多应用对象锁的锁状态只会持续很短一段时间,为了这一段很短的时间频繁地阻塞和唤醒线程是非常不值得的。
自旋锁
自旋锁适用于锁保护的临界区很小的情况,临界区很小的话,锁占用的时间就很短。自旋等待不能替代阻塞,虽然它可以避免线程切换带来的开销,但是它占用了CPU处理器的时间。如果持有锁的线程很快就释放了锁,那么自旋的效率就非常好,反之,自旋的线程就会白白消耗掉cpu的资源,这样反而会带来性能上的浪费。所以说,自旋等待的时间(自旋的次数)必须要有一个限度,如果自旋超过了定义的时间仍然没有获取到锁,则应该被挂起。
自旋锁在JDK 1.4.2中引入,默认关闭,但是可以使用-XX:+UseSpinning开开启,在JDK1.6中默认开启。同时自旋的默认次数为10次,可以通过参数-XX:PreBlockSpin来调整。在JDK1.7后去掉此参数,由jvm控制,自适应性规则如下:
1.如果平均负载小于CPUs则一直自旋
2.如果有超过(CPUs/2)个线程正在自旋,则后来线程直接阻塞
3.如果正在自旋的线程发现Owner发生了变化则延迟自旋时间(自旋计数)或进入阻塞
4.如果CPU处于节电模式则停止自旋
5.自旋时间的最坏情况是CPU的存储延迟(CPU A存储了一个数据,到CPU B得知这个数据的时间有延迟)
6.自旋时会适当放弃线程优先级之间的差异
线程如果自旋成功了,那么下次自旋的次数会更加多,因为虚拟机认为既然上次成功了,那么此次自旋也很有可能会再次成功,那么它就会允许自旋等待持续的次数更多。反之,如果对于某个锁,很少有自旋能够成功,那么以后这个锁的自旋次数会减少甚至省略掉自旋过程,以免浪费处理器资源。随着JDK版本的更新,虚拟机变得越来越聪明。优先使用高版本JDK程序性能更能得到保障。
【浅谈Java】本篇为synchronized的后续,主要对上篇文章的补充说明。感谢阅读,求关注,求点赞。随手点赞,留有余香。学习是冰冻三尺非一日之寒,愿与诸君共勉励。