• 一个自旋锁的栗子


      一直以来不是怎么清楚自旋锁,最近有点时间,好好的学习了一下;

      所谓的自旋锁在我的理解就是多个线程在尝试获取锁的时候,其中一个线程获取锁之后,其他的线程都处在一直尝试获取锁的状态,不会阻塞!!!那么什么叫做一直尝试获取锁呢?就是一个循环,比较经典的是AtomicInteger中的一个updateAndGet方法,下图所示(当然也可以直接看unsafe类中的getAndAddInt等类似方法);

      我们可以看出在while循环中使用CAS去尝试更新一个变量,如果更新失败,就会一直在这个循环中一直在尝试;成功的话,就可以到最后的return语句;

      由此我们可以大概知道如果自旋的线程过多,那么CPU的资源就会被大量消耗!!!

      顺便提一个东西叫做原子引用,官方提供了AtomicInteger,AtomicBoolean等原子类,那么如果我们自己定义的类也需要有原子性怎么办呢?所以官方提供了一个AtomicReference类,可以将我们自己定义的类封装一下,就成了我们自己的原子类,例如AtomicReference<Student> atomicReference = new AtomicReference<>();,然后我们对Student的实例进行CAS各种CAS操作;

      栗子:

    package TestMain;
    
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicReference;
    
    @Slf4j
    public class TestMain80 {
        //一个Thread类的原子引用
        AtomicReference<Thread> atomicReference = new AtomicReference<>();
    
        //加锁的方法
        public void myLock() {
            Thread currentThread = Thread.currentThread();
            log.info("myLock--Thread:{}", currentThread.getName());
            //这个就是自旋锁的核心,利用CAS比较当前原子引用中是否为null,如果是null,就把当前线程A放到里面去,
            // 此时线程B再到这里,那么就会CAS失败,一直在while循环中
            while (!atomicReference.compareAndSet(null, currentThread)) {
    
            }
        }
    
        //解锁的方法
        public void myUnlock() {
            Thread currentThread = Thread.currentThread();
            //CAS比较原子引用中是不是线程A,是的话就更新为null,此时在上面while中一直在自旋的线程B就可以跳出来了
            atomicReference.compareAndSet(currentThread, null);
            log.info("myUnlock--Thread:{}", currentThread.getName());
        }
    
        public static void main(String[] args) {
            TestMain80 testMain80 = new TestMain80();
    
            //线程A,首先加锁,然后等3秒中,然后释放锁
            new Thread(() -> {
                testMain80.myLock();
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                testMain80.myUnlock();
            }, "A").start();
    
            //主线程等1秒,保证A线程先执行
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            //线程B,加锁再释放锁
            new Thread(() -> {
                testMain80.myLock();
                testMain80.myUnlock();
            }, "B").start();
    
    
        }
    }

      上面的就是一个自旋锁的栗子,执行结果中首先是执行A线程的myLock方法,获取锁成功,之后的B线程虽然也会执行mylock方法,但是会在while循环中一直阻塞,直到线程A调用了myUnlock方法释放锁,最后两行才会打印出来;

  • 相关阅读:
    C++11智能指针处理Array对象
    jquery代码链实现延时执行代码的较优雅办法
    [Leetcode Weekly Contest]271
    macOS输入法提示条消失问题
    MacBook手势失灵的问题
    zsf bash_profile 区别
    Git放弃本地修改
    :disabled="add_content === changeIf ? true:false"
    将已加入的文件忽略
    nginx配置nacos集群代理机制
  • 原文地址:https://www.cnblogs.com/wyq1995/p/12539853.html
Copyright © 2020-2023  润新知