概念
自旋锁(spinlock):是指尝试获取锁的线程不会立刻阻塞,而是采纳循环的形式去尝试获取锁。
- 之前学过的CAS,底层应用的就是自旋锁,自旋就是屡次尝试,屡次拜访,不会阻塞的状态就是自旋。
优缺点
长处:循环比拟获取直到胜利,没有相似wait的阻塞。还能缩小线程上下文切换的耗费
毛病:当一直自旋的线程越来越多的时候,会因为执行while循环不断的耗费CPU资源
手写自旋锁
自旋的实质就是CAS办法和while循环
public class SpinLockDemo { // 原子援用线程 AtomicReference<Thread> atomicReference = new AtomicReference<>(); public void myLock() { Thread thread = Thread.currentThread(); // 返回对以后正在执行的线程对象的援用 System.out.println(Thread.currentThread().getName() + "进来了");/* 首个线程进来,发现atomicReference是null,就变为这个线程。而后取反变为false,跳出循环期待。 如果发现卫生间外面还有人,就始终循环始终等,直到卫生间外面没人。 */ while (!atomicReference.compareAndSet(null, thread)) { //没跳出就始终循环 } } public void myUnlock() { Thread thread = Thread.currentThread(); // 我进来要解锁,而后变为null给下一个人用 atomicReference.compareAndSet(thread, null); System.out.println(Thread.currentThread().getName() + "调用myUnlock办法"); }
测试
public static void main(String[] args) throws InterruptedException { SpinLockDemo spinLockDemo = new SpinLockDemo(); // 我A线程进去占用这把锁,而后霸占5s new Thread(() -> { spinLockDemo.myLock(); TimeUnit.SECONDS.sleep(5); spinLockDemo.myUnlock(); }, "线程A").start(); // 主线程main暂停1s,保障A线程先启动 TimeUnit.SECONDS.sleep(1); // 我B线程再进去循环期待这把锁 new Thread(() -> { spinLockDemo.myLock(); spinLockDemo.myUnlock(); }, "线程B").start(); }
运行后果
线程A进来了 //A进来了,A要占用5s线程B进来了 //B也进来了,发现卫生间有人,循环期待A进去线程A调用myUnlock办法 //A进去了线程B调用myUnlock办法 //B占用完锁,也进去了