CAS - 自定义自旋锁

        前面一篇文章我们学习了CAS的基本原理。CAS是实现自旋锁的基础,CAS利用CPU指令保证的操作的原子性,已达到锁的效果。至于自旋,就是字面意思“自己旋转”,是指尝试获取共享资源的线程不会立即阻塞,而是采用循环的方法尝试去获取锁,当线程发现共享资源被占用,就会不断的判断锁的状态,知道获取。这样的好处就是减少线程上下文切换的消耗,缺点是消耗CPU资源。

自己实现一个自旋锁(SpinLock)

        前面一篇文章我们学习的AtomicInteger的基本实现,我们是用和其类似的AtomicReference来实现我们自定义的自旋锁。AtomicReference和AtomicInteger差不多,都是使用CAS来实现的,只不过AtomicReference承载的是一个任意对象,而AtomicInteger是一个Integer。

/**
 * @author tlh
 * @date 2023/8/7 21:17
 */
public class SpinLockDemo {

    private AtomicReference<Thread> atomicReference = new AtomicReference<>();

    /**
     * 上锁
     */
    public void lock() {
        Thread currentThread = Thread.currentThread();
        while (!atomicReference.compareAndSet(null, currentThread)) {
            System.out.println(currentThread.getName() + " 正在尝试获取🔒");
        }
        System.out.println(currentThread.getName() + " 获得了🔒资源");
    }
    /**
     * 释放锁
     */
    public void unLock() {
        Thread currentThread = Thread.currentThread();
        atomicReference.compareAndSet(currentThread, null);
        System.out.println(currentThread.getName() + " 任务完成,释放🔒资源");
    }
 }

        我们自定义的自旋锁SpinLockDemo,有一个AtomicReference的属性和有两个方法lock()方法和unLock()方法。

lock()方法

        lock()方法里面有一个while循环,循环里面适应AtomicReference的compareAndSet()方法实现自旋:第一个线程进来,先判断AtomicReference实例里面是否没有存在线程对象,如果不存在的话就将当前线程保存起来(获得锁的控制权)。如果存在,就不停的重试(自旋)。

unLock()方法

        unLock()方法,将当前AtomicReference实例中的线程重置为空(让出锁的控制权)。

使用自定义的SpinLock

 public static void main(String[] args) {

        SpinLockDemo spinLock = new SpinLockDemo();

        new Thread(() -> {
            spinLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 做自己的任务");
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinLock.unLock();
        }, "A").start();


        //保证A线程比B线程先获得锁
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            spinLock.lock();
            System.out.println(Thread.currentThread().getName() + " 做自己的任务");
            spinLock.unLock();
        }, "B").start();
    }

        A线程和B线程抢占我们自定义的自旋锁,为了让A线程先获得锁的控制权,我们在A线程start后暂停了100毫秒。

        打印结果:

A 获得了🔒资源
A 做自己的任务
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒

......

B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
B 正在尝试获取🔒
A 任务完成,释放🔒资源
B 获得了🔒资源
B 做自己的任务
B 任务完成,释放🔒资源

        我们看到结果,A线程先获得锁资源,B线程在A线程没有释放锁资源之前一直处于“尝试获取🔒资源”的状态。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值