美文网首页
JUC之自旋锁

JUC之自旋锁

作者: 西界__ | 来源:发表于2020-12-31 10:16 被阅读0次

自旋锁

<mark>是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好吃是减少线程上下文切换的消耗,缺点是循环会消耗CPU。</mark>

自旋的方式我们在查看AtomicInteger的底层时候就已经体验过了

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
      //自旋
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

手写自旋锁

首先原子引用线程类AtomicReference<Thread> atomicReference = new AtomicReference<>();

接着编写myLock()首先通过Thread.currentThread();获取到当前线程thread,接着通过原子引用的compareAndSet(null,thread);比较预期值和真实值是否为null,如果为null则更新值为thread,返回true,取反为false退出循环。否则不为null则返回为false,取反为true一直循环,直到为null。从而达到自旋的效果!

myUnLock方法则也是一开始通过Thread.currentThread();获取到当前线程thread,接着通过原子引用的compareAndSet(thread,null);比较预期值和真实值是否为同一个threadl,相同则更新成功为null。(这里解锁方法没有完善,线程没有上锁直接解锁也可以正常执行该方法打印语句退出)

这里优化一下,我们通过对compareAndSet(thread,null);的结果取反做为if的判断条件,只有当compareAndSet(thread,null);的结果为false时,也就是期望与真实值不符时抛出运行时异常throw new RuntimeException("解锁出现了异常!");

当我们直接不上锁而解锁时抛出异常

测试成功,开始正常情况测试!

通过主线程的睡眠,确保每次都是线程A执行,线程A首先获取到自旋锁,接着暂停5秒,在这5秒期间线程B想获取到锁,但是此时的锁在线程A中经过while循环判断不符合,所以线程B一直处于采用循环的方式去尝试获取锁。知道线程A继续开始执行,释放了锁。线程B才能获取到锁并后续将它释放!!

运行验证结果~

代码测试正确!!!

public class SpinLockDemo {
    //原子引用线程类
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    public static void main(String[] args) {
        SpinLockDemo spinLockDemo = new SpinLockDemo();

        new Thread(() -> {
            spinLockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinLockDemo.myUnLock();
        }, "AA").start();

        //保证每次AA线程先执行,BB后执行
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            spinLockDemo.myLock();
            spinLockDemo.myUnLock();
        }, "BB").start();

    }

    public void myLock() {
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "\t come in");

        while (!atomicReference.compareAndSet(null, thread)) {

        }
    }

    public void myUnLock() {
        Thread thread = Thread.currentThread();
        if (!atomicReference.compareAndSet(thread, null)){
            throw new RuntimeException("解锁出现了异常!");
        }
        System.out.println(Thread.currentThread().getName() + "\t invoked myUnlock()");
    }
}

相关文章

  • JUC之自旋锁

    自旋锁 是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好吃是减少线程上下文切换的消耗,缺...

  • 手写Ribbon轮询算法

    个人学习笔记 原理+JUC(CAS+自旋锁的复习) Ribbon负载均衡的轮询算法: rest接口第几次请求数%服...

  • 多线程笔记-锁(待续)

    概述 CAS算法 一般情况下是一个自旋操作,即不断的重试 自旋锁 《 面试必备之深入理解自旋锁》[https://...

  • iOS 开发中加锁

    [1].OSSpinLock 自旋锁 [1]自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被...

  • JUC源码循序渐进

    目录 必读篇 JUC源码分析—CAS和Unsafe JUC源码分析—AQS JUC锁篇 JUC源码分析-JUC锁(...

  • 关于自旋锁

    自旋锁是什么? spinlock,不断的自旋(自我循环)尝试获得锁。参考文档:Java中的自旋锁 自旋锁的实现 自...

  • 自旋锁与互斥锁

    自旋锁(Spin lock) 自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保...

  • 线程同步

    一、临界资源 加锁会导致运行时间的增长 二、互斥锁 三、自旋锁 实验发现【自旋锁】的效率较高自旋锁 自旋锁加入休眠...

  • CLH并发队列

    1 什么是自旋锁和互斥锁? 由于CLH锁是一种自旋锁,那么我们先来看看自旋锁是什么? 自旋锁说白了也是一种互斥锁,...

  • JAVA基础—JUC包(java.util.concurrent

    1. JUC - CountDownLatch 倒计时锁 运行结果 2. JUC之Semaphore信号量 运行结...

网友评论

      本文标题:JUC之自旋锁

      本文链接:https://www.haomeiwen.com/subject/wgddnktx.html