zoukankan      html  css  js  c++  java
  • AbstractQueuedSynchronizer

    管程

     一个管程定义了一个数据结构和能够并发进程所执行的一组操作,这组操作能同步进程和改变管程中的数据。

    问题及解决

    AQS是一个管程,用于同步不同线程。在实现功能的过程中,需要考虑以下几个问题:

    1. 在高并发情况下如何确定当前线程是否能够进行后续操作。
    2. 如果不能进行后续操作,是否需要阻塞;如果阻塞,该如何唤醒。
    3. 如何对多个线程进行管理,是否需要实现条件等待及如何实现条件等待。

    针对以上几个问题,AQS给出了解决方案:

    1. 使用一个全局的状态,通过判断全局的状态来确定线程是否可以进行后续操作。这个全局的状态为volatile的,通过使用CAS操作来实现对状态的修改,CAS相关的功能由Unsafe类提供。
    2. AQS维护一个同步队列,在同步队列中,如果线程不允许进行后续操作,则进行阻塞,阻塞操作及唤醒操作由LockSupport调用Unsafe类的方法提供。
    3. AQS维护条件队列,通过与AQS的配合,完成条件等待与唤醒操作。

    结构

    AQS

    head:始终指向获得了锁的节点,它不会被取消。新的线程获得锁之后,之前获得锁的节点从队列中出队。

    tail:负责无锁地实现一个链式结构,采用CAS+轮询的方式。节点的入队操作都在tail节点。

    state:AQS当前的状态。

    Node

    SHARED:表示共享模式。

    EXCLUSIVE:表示独占模式。

    waitStatus:节点等待状态。CANCELLED=1,表示取消状态。SIGNAL=-1,表示后续节点需要被唤醒。CONDITION=-2,表示线程正处在条件等待状态。PROPAGATE=-3,表示释共享锁时,需要唤醒后续节点。

    prev:指向队列中的前一个节点。

    next:指向队列中的下一个节点。

    thread:把一个节点关联到一个线程。

    nextWaiter:指向在条件队列中的下一个正在等待的节点,是给条件队列使用的。值得注意的是条件队列只有在独享状态下使用。

    ConditionObject

    firstWaiter:指向条件队列的队首节点。

    lastWaiter:指向条件队列的对尾节点。

    工具类

    LockSupport

    利用Unsafe直接操作内存来存取对象的能力来设置blockers。Unsafe.objectFieldOffset可以获得某个字段在对象所在内存的offset,有了这个offset,就可以通过对象的引用来找到字段所在的实际内存地址。Thread的parkBlocker属性用来指出当前线程是在哪个对象上阻塞。park方法需要指明锁对象。park方法先setBlocker,标记当前线程是在哪个锁对象上等待,然后调用Unsafe的park方法,当Unsafe的park方法返回时表示已经退出等待,就把blockers设置为null。

    Unsafe

    Unsafe提供了三类与并发相关的方法:

    1. CAS方法。如compareAndSwapObject()、compareAndSwapInt()、compareAndSwapLong()。
    2. 操作条件队列的方法。如park()、unpark()。
    3. 存取volatile变量的方法。如getObjectVolatile()、putObjectVolatile()、getIntVolatile()、putIntVolatile()等。

    操作

    获取操作
    
    while(状态不允许获取操作) {
        if (需要阻塞获取请求) {
            如果当前线程不在同步队列中,那么将其插入队列
            阻塞当前线程
        } else {
            返回失败
        }
    }
    可能更新同步器状态
    如果线程位于同步队列,则将其移出队列
    返回成功
    
    
    释放操作
    更新同步器状态
    if (新的状态允许某个被阻塞的线程获取成功) { 解除队列中一个或多个线程的阻塞状态 }

    方法

     

    扩展

    子类扩展时有两种类型,一种是公平的同步器,另一种是非公平的同步器。所谓的非公平,不是说不适用队列来维护阻塞操作,而是说在竞争时,后来的线程可以不考虑在同步队列中的线程而直接竞争资源。同步器竞争失败后,都需要进入AQS的同步队列进行等待,而同步队列是先来先服务的公平的队列。

    参考资料

    1.《聊聊高并发》

    2.《The j.u.c Synchronizer Framework》

  • 相关阅读:
    Luogu P1160 【队列安排】
    Luogu P1566 【加等式】
    CF614A 【Link/Cut Tree】
    AT994 【11の倍数】
    Luogu P2310 【loidc,看看海】
    CF401D 【Roman and Numbers】
    【[国家集训队]小Z的袜子】
    UVA10212 【The Last Non-zero Digit.】
    Luogu P3384 【【模板】树链剖分】
    20161005 NOIP 模拟赛 T2 解题报告
  • 原文地址:https://www.cnblogs.com/qhdxqxx/p/8875853.html
Copyright © 2011-2022 走看看