利用CAS实现自旋锁

手写自旋锁
  1. 循环比较获取直到成功为止,没有类似于wait的阻塞
  2. 通过CAS操作完成自旋锁,A线程先进来调用myLock方法自己持有锁5秒,B随后进来发现当前有线程持有锁,不是null,所以只能通过自旋等待,直到A释放锁后B随后抢到
public class SpinLockDemo {

    //现在的泛型装的是Thread,原子引用线程
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    /**
     * 加锁方法
     */
    public void addLock() {
        Thread thread = Thread.currentThread();
        System.out.println("threadName = " + thread.getName() + "\t come in ");
        //开始利用CAS自旋,期望值是null,更新为当前线程。如果是null,更新为当前线程,否则自旋
        while (!atomicReference.compareAndSet(null, thread)) {
            System.out.println("线程名 " + thread.getName() + " ,正在自旋,不断通过CAS尝试获取锁");
        }
    }

    /**
     * 解锁方法
     */
    public void cancelLock() {
        Thread thread = Thread.currentThread();
        System.out.println("threadName = " + thread.getName() + "\t come out ");
        //自己用完了后,把atomicReference变成null
        atomicReference.compareAndSet(thread, null);
        System.out.println("threadName = " + thread.getName() + "\t 已完成解锁 ");
    }
}

创建两个线程 t1,t2 分别调用加锁和解锁的方法

    public static void main(String[] args) {
        SpinLockDemo spinLockDemo = new SpinLockDemo();
        new Thread(() -> {
            //加锁
            spinLockDemo.addLock();
            System.out.println("t1线程 执行业务逻辑--> 赚钱赚钱赚钱赚钱赚钱赚钱赚钱操作");
            try {
                //1毫秒的时间内都在赚钱
                TimeUnit.MILLISECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //解锁
            spinLockDemo.cancelLock();

        }, "t1").start();

        new Thread(() -> {
            //加锁
            spinLockDemo.addLock();
            System.out.println("t2线程 执行业务逻辑--> 把钱存进银行的操作");
            //解锁
            spinLockDemo.cancelLock();
        }, "t2").start();
    }

上述代码执行结果如下

threadName = t1	 come in 
t1线程 执行业务逻辑--> 赚钱赚钱赚钱赚钱赚钱赚钱赚钱操作
threadName = t2	 come in 
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
threadName = t1	 come out 
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
threadName = t1	 已完成解锁 
t2线程 执行业务逻辑--> 把钱存进银行的操作
threadName = t2	 come out 
threadName = t2	 已完成解锁 

由此可知CAS的方法加锁会频繁自旋,占用CPU,过于浪费系统资源

将t1线程的睡眠时间替换成100ms
TimeUnit.MILLISECONDS.sleep(100);
查看cpu的使用情况如下:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值