乐趣区

关于java:10Java锁之自旋锁

概念

自旋锁(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 占用完锁,也进去了
退出移动版