基于AQS队列对锁的一些认识

AQS

AQS(AbstractQueuedSynchronizer)

    简单来说AQS是基于CLH(FIFO)队列结构实现的,通过自旋获取锁,用CAS更新锁的状态的一个同步队列

AQS的核心思想

    如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,就将当前的任务节点加入队列,然后通过自旋不断的获取状态。如果获取到状态后,就将当前的节点设置为头结点,意味着当前任务已经获取到锁了。

什么是CLH队列

    CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。

自旋锁

通俗来讲:自旋就是循环,也就是通过轮询来更新锁

简单的自旋锁的实现:

public class SpinLock {
          
   
    private AtomicReference<Thread> cas = new AtomicReference<Thread>();
    public void lock() {
          
   
        Thread current = Thread.currentThread();
        // 利用CAS
        while (!cas.compareAndSet(null, current)) {
          
   
            // DO nothing
        }
    }
    public void unlock() {
          
   
        Thread current = Thread.currentThread();
        cas.compareAndSet(current, null);
    }
}

CAS

CAS(Compare And Swap/Set)比较并交换,CAS 算法的过程是这样:它包含 3 个参数CAS(V,E,N)。V 表示要更新的变量(内存值),E 表示预期值(旧的),N 表示新值。当且仅当 V 值等于 E 值时,才会将 V 的值设为 N,如果 V 值和 E 值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。最后,CAS 返回当前 V 的真实值。

CAS是一种乐观锁,它总是认为自己可以成功完成操作。当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。基于这样的原理,CAS 操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。

经验分享 程序员 微信小程序 职场和发展