自旋锁

概念和意义

尝试获取锁的线程不会立即阻塞(no wait),而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环消耗cpu

 

unsafe中的源码

//unsafe.getAndAddInt
putlic final int getAndAddInt(Object var1,long var2, int var4){
    int var5;
    do{
        var5 = this.getVolatile(var1,var2);
    }while(!this.compareAndSwapInt(var1,var2,var5,var5+var4));
    return var5;
}

var1:对象

var2:偏移地址

var5:通过var1和var2得到内存中的变量

会持续获得内存var2中的变量,如果取得的值被修改了,就会重复这一步骤,直到拿到正确的值,然后将值设置为var5+var4。

 

使用AtomicReference模拟自旋锁

public class SpinLockTest {
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    // 自定义自旋锁
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"等待拿锁");
        while(!atomicReference.compareAndSet(null,thread)){
        }
        System.out.println(Thread.currentThread().getName()+"拿到了");
    }
    // 自定义解锁
    public void myUnlock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"释放了锁");
        atomicReference.compareAndSet(thread,null);
    }

    public static void main(String[] args) {
        SpinLockTest spin = new SpinLockTest();

        // 线程AA拿锁5秒后释放
        new Thread(()->{
            spin.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spin.myUnlock();
        },"AA").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 线程BB尝试拿锁,然后释放
        new Thread(()->{
            spin.myLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spin.myUnlock();
        },"BB").start();

    }
}

 

posted @ 2021-04-18 15:11  wsZzz1997  阅读(58)  评论(0编辑  收藏  举报