Java面试题(十) 揭秘Java大陆的神秘家族“锁”之一族(三) 手写自旋锁

一. 手写自旋锁

自旋锁好处,循环比较获取直到成功为止,没有类似wait的阻塞

1. 实现步骤

 通过CAS操作完成自旋锁,
 T1线程先进来调用mylock方法自己持有锁5秒钟,
 T2随后进来发现当前有线程持有锁,不是null,所以只能通过自旋等待,
 直到T1释放锁后T2随后抢到线程资源

Java底层源码是这样实现自旋锁的

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;
    }

我们也可以模范其精华,先把获得锁和释放锁写出来,很容易,需要使用到前面的文章 解密CAS 中提到过atomicReference.compareAndSet()方法。

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

    public void myLock() {
        //获得锁
        //当前线程
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "\t myLock (●'◡'●)");
        //只有当值比较交换完才会返回true,在取反才会退出循环
        while (!atomicReference.compareAndSet(null, thread)){

        }
    }

    public void myUnLock() {
        //释放锁
        //当前线程
        Thread thread = Thread.currentThread();
        //将当前线程置为null,释放锁
        atomicReference.compareAndSet(thread, null);
        System.out.println(Thread.currentThread().getName() + "\t myUnLock o(* ̄▽ ̄*)ブ");
    }

测试

 public static void main(String[] args) {

        SpinLockDemo spinLockDemo = new SpinLockDemo();

        new Thread(() -> {
            //获得锁
            spinLockDemo.myLock();
            //睡 5秒
            try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
            //释放锁
            spinLockDemo.myUnLock();
        }, "T1").start();

        //保证 T1线程先启动
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

        new Thread(() -> {
            //获得锁
            spinLockDemo.myLock();
            //释放锁
            spinLockDemo.myUnLock();
        }, "T2").start();
    }

运行结果
在这里插入图片描述
大体描述一下执行过程

首先T1先去获得锁,在获得锁后,他需要等待5秒再去执行释放锁的方法,
而这时T2也去获得锁,但是CAS的过程中,发现锁不能被交换,也就是锁不能被获得,
只能老老实实的等待T1线程结束
等T1释放锁后,T2才能获得锁,然后在释放锁。

总结:自旋锁手写过程并不复杂,只是需要我们对compareAndSet()方法熟悉。

下一篇:手写读写锁

猜你喜欢

转载自blog.csdn.net/w_x_A__l__l/article/details/106874541
今日推荐