我们知道,无论是 synchronized 还是 lock 锁,它们都有一个同步监视器,也就是锁。
当一个线程 进入临界区,访问共享变量,就要获取这个锁;
其它线程也要访问这个共享变量,发现锁被占用了,这时有两种操作方式:
- 将自己挂起,等锁释放后再恢复,但这会给 jvm 的并发带来很大压力,
- 对共享变量的访问往往不需要很长时间,没必要为了这点时间就去挂起和恢复线程
- 如果你的 cpu 是多核的,支持多个线程并行,当一个线程获取锁,另一个线程并不释放 cpu,而是执行一个忙循环,一直等待锁被释放,这就是 自旋锁,一旦锁释放,再继续执行,这样就避免了线程的挂起与恢复。
如果锁被占用的时间很短,自旋锁的效果会非常好,避免线程切换的开销。
但是万一锁占用的时间很长呢,自旋锁就会一直执行循环,一直占用 cpu,无疑是浪费 cpu 资源。
jdk 中,自旋锁默认自旋 10 次(可通过 -XX:PreBlockSpin 自行修改),10次还没获得锁,就挂起该线程。
自适应自旋:
在 jdk6 中,对自旋锁进行了优化,引入了 自适应自旋;
这意味着 自旋次数 并不是固定的了,而是由上一次 对同一个锁的自旋时间以及锁的占有者的状态来决定。
比如 上一次对这个锁的自旋时间很短,很快就获得了这个锁,那就认为 这次自旋也会很快就获得锁,于是就愿意花时间去自旋等待;
如果对于某个锁,自旋很少成功获得锁,说明这个锁的占用时间很长,可能就直接挂起这个线程,不进行自旋了。

946

被折叠的 条评论
为什么被折叠?



