最近看视频刚好看到关于 Java 自旋锁相关内容,结合实例代码做一个记录
本文参考地址:面试必备之深入理解自旋锁
什么是自旋锁
自旋锁是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
如何实现自旋锁
简单例子 🌰
下面代码是一个简单的自旋锁例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class SpinLock { private AtomicReference<Thread> cas = new AtomicReference<Thread>(); public void lock() { Thread current = Thread.currentThread(); while (!cas.compareAndSet(null, current)) { } } public void unlock() { Thread current = Thread.currentThread(); cas.compareAndSet(current, null); } }
|
存在的问题:
1、某个线程持有锁时间过长时,会导致其他线程一直处于等到状态,导致徒增 CPU 消耗
2、存在不公平情况,即等待时间长的线程不一定能优先获得锁
可重入锁🔐 和 不可重入锁🔐
上述代码存在的问题:当线程 A 持有锁时,在线程 A 释放锁之前不可再次获得锁。而可重入锁需要保证线程 A 再次获取锁时,也有机会获得锁对象。
优化代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class Cas { private AtomicReference<Thread> cas = new AtomicReference<Thread>(); private int count;
public void lock() { Thread currentThread = Thread.currentThread(); if (currentThread == cas.get()) { count++; return; } while (cas.compareAndSet(null, currentThread)) { } }
public void unlock() { Thread currentThread = Thread.currentThread(); if (currentThread == cas.get() && count > 0) { count--; } else { cas.compareAndSet(currentThread, null); } } }
|
增加了一个线程「锁」计数器,当 A 线程的重入数量为0时,释放当前锁资源。