你知道啥是自旋锁吗?
- 普通的锁,如果条件不达成就会进入睡眠
- 自旋锁,它不会放弃CPU时间片,而是不停的尝试获取锁,直到成功,适用于并发度不高,代码指向短的场景
解释
- “自旋”可以理解我自我旋转,这里的“旋转”指的是循环,就是自己不停的循环,直到目标达成。而普通的锁,如果获取不到锁就进入睡眠
- 自旋锁,它不会放弃CPU时间片,而是通过自选等待锁的释放。也就是说,它会不停的再次尝试获取锁,如果失败就再次尝试,直到成功获取锁
- 而非自旋锁,如果获取不到所,它就会把线程阻塞,直到持有这把锁的另一线程释放了锁,于是CPU再把之前的线程恢复,让这个线程再次尝试去获取这把锁。如果再次失败,就再次线程休眠,如果成功,就获取同步资源
自旋锁的好处:
- 阻塞和唤醒线程都需要高昂的开销,如果同步代码块中的内容不复杂,那么可能转换线程带来的开销比实际业务代码执行的开销还要打大
- 在很多场景下,可能我们的同步代码块的内容并不多,所以需要的执行时间也很短,如果我们仅仅为了这点时间就去切换线程状态,那么其实不如让线程不切换状态,而是让它自旋地尝试获取锁,等待其他线程释放锁,有时我只需要稍等一下,就可以避免上下文切换等开销,提高了效率
自旋锁的缺点
- 它最大的缺点在于虽然避免了线程切换的开销,但是它在避免线程切换开销的同时也带来了新的开销,因为它需要不停的去尝试获取锁。如果这把锁一直不能被释放,那么这种尝试只是无用的尝试,会白白浪费处理器资源
- 也就是说,虽然一开始自旋锁的开销低于线程切换,但是随着时间的增加,这种开销也是水涨船高,后期甚至会超过线程切换的开销,得不偿失
使用场景
- 适用于并发度不是特别高的场景,以及临界区比较短小的情况,这样为我们可以利用线程切换来提高效率
- 如果临界区很大,线程一旦拿到锁,很久才会释放的话,那就不适合自旋锁
锁的可重入不可重入
- 可重入锁:当一个线程获取锁之后,这个线程可以在此获取本对象上的锁
- 不可重入锁:当一个线程获取锁之后,必须该线程释放锁才可以获取其他对象的锁