AbstractQueuedSynchronizer文档翻译

   一、概述 

        提供一个框架,以实现依赖于先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等)。此类旨在为大多数依赖单个原子int值表示状态的同步器提供有用的基础。子类必须定义更改此状态的受保护方法,并且定义该状态对于获取或释放此对象而言意味着什么。鉴于这些,此类中的其他方法将执行所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()、setState(int) 和 compareAndSetState(int, int) 方法来操作以原子方式更新的 int 值。

       子类应定义为用于实现其所在类的同步属性的非公共内部帮助器类。AbstractQueuedSynchronizer没有实现任何同步接口。相反,它定义了acquireInterruptible之类的方法,可以通过具体的锁和相关的同步器适当地调用这些方法以实现其公共方法。

        此类支持默认的exclusive独占模式和shared共享模式之一。当以独占方式进行获取时,其他线程尝试进行的获取将无法成功。由多个线程获取的共享模式可能(但不一定)成功。该类不理解这些区别,只是从机械意义上说,当共享模式获取成功时,下一个等待线程(如果存在)也必须确定它是否也可以获取。在不同模式下等待的线程共享相同的FIFO队列。通常,实现子类仅支持这些模式之一,但两种模式都可以在ReadWriteLock 中发挥作用。仅支持排他或仅共享模式的子类无需定义支持未使用模式的方法。

       此类定义了一个嵌套的ConditionObject类,可由支持独占模式的子类用作Condition实现,isHeldExclusively报告是否相对于当前线程专有地保留同步,使用当前 getState 值调用 release(int) 方法则可以完全释放此对象;如果给定保存的状态值,那么 acquire(int) 方法可以将此对象最终恢复为它以前获取的状态。否则,没有别的AbstractQueuedSynchronizer方法会创建这样的条件,因此,如果无法满足此约束,则不要使用它。AbstractQueuedSynchronizer.ConditionObject 的行为当然取决于其同步器实现的语义。

       此类提供了内部队列的检查,检测和监视方法,还为 condition 对象提供了类似方法。。可以根据需要使用用于其同步机制的 AbstractQueuedSynchronizer 将这些方法导出到类中。

      此类的序列化仅存储基础原子整数维护状态,因此反序列化的对象具有空线程队列。需要序列化性的典型子类将定义一个readObject方法,该方法可在反序列化时将其恢复为已知的初始状态。

二、用法

        要将此类用作同步器的基础,需要适当地重新定义以下方法,这是通过使用 getState()、setState(int) 和/或 compareAndSetState(int,int) 方法来检查和/或修改同步状态来实现的:

  1. tryAcquire
  2. tryRelease
  3. tryAcquireShared
  4. tryReleaseShared
  5. isHeldExclusively

       默认情况下,这些方法中的每一个都会引发 UnsupportedOperationException。这些方法的实现必须在内部是线程安全的,并且通常应简短且不阻塞。定义这些方法是使用此类的唯一 受支持的方式。所有其他方法都声明为final,因为它们不能独立变化。

        您可能还会发现从AbstractOwnableSynchronizer继承的方法对于跟踪拥有独占同步器的线程很有用。鼓励您使用它们,这将启用监视和诊断工具,以帮助用户确定哪些线程持有锁。

       即使此类基于内部FIFO队列,它也不会自动执行FIFO获取策略。独占同步的核心采用以下形式:(共享模式相似,但可能涉及级联信号)

  Acquire:

     //获取失败
      while (!tryAcquire(arg)) {

         如果线程尚未排队,则将其加入队列
         可能阻塞当前线程;
      }
 
  Release:
      if (tryRelease(arg))

          取消第一个排队线程的阻塞

      因为要在加入队列之前检查线程的获取状况,因此新获取线程可能会在被阻塞和排队的其他线程之前插入。但是,如果需要,您可以定义 tryAcquire和/或 tryAcquireShared来通过内部调用一种或多种检查方法来禁用插入,从而提供公平 FIFO获取顺序。特别是,如果hasQueuedPredecessors(一种专门为公平同步器设计的方法)返回 true,则大多数公平同步器都可以定义tryAcquire返回 false。其他变化是可能的。

       对于默认插入(也称为greedy(贪婪),renouncement(拒绝)和 convoy-avoidance(避开车队))策略,吞吐量和可伸缩性通常最高。尽管不能保证这是公平的或是无偏向的,但允许更早加入队列的线程先于更迟加入队列的线程再次争用资源,并且相对于传入的线程,每个参与再争用的线程都有平等的成功机会。此外,尽管从一般意义上说,获取并非“自旋”,它们可以在阻塞之前对用其他计算所使用的 tryAcquire 执行多次调用。如果仅短暂地保持排他同步时,这为自旋提供了最大的好处,但不是这种情况时,也不会带来很多负担。如果需要这样做,那么可以使用“快速路径”检查来先行调用 acquire 方法来扩充此功能,如果可能不需要争用同步器,则只能通过预先检查 hasContended() 和/或 hasQueuedThreads() 来确认这一点。

      通过特殊化其同步器的使用范围,此类为部分同步化提供了一个有效且可伸缩的基础,同步器可以依赖于 int 型的 state、acquire 和 release 参数,以及一个内部的 FIFO 等待队列。这些还不够的时候,可以使用 atomic 类、自己的定制 Queue 类和 LockSupport 阻塞支持,从更低级别构建同步器。

三、样例

       这是一个不可重入的互斥锁定类,使用值0表示解锁状态,使用值1表示锁定状态。尽管不可重入锁并不严格要求记录当前所有者线程,但无论如何,此类会这样做,以使使用情况更易于监视。它还支持条件并公开一种检测方法

class Mutex implements Lock, java.io.Serializable {
    
    /**
     * 内部帮助器类
     */
    private static class Sync extends AbstractQueuedSynchronizer {
        // 记录是否持有锁
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        // 获取锁如果state值为0
        @Override
        public boolean tryAcquire(int acquires) {
            assert acquires == 1; // Otherwise unused
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        //释放锁通过设置state为0
        @Override
        protected boolean tryRelease(int releases) {
            assert releases == 1; // Otherwise unused
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        /**
         * Provides a Condition
         */
        Condition newCondition() {
            return new ConditionObject();
        }
        
        /**
         * Deserializes properly
         */
        private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    /**
     * 同步对象完成所有艰苦的工作。我们只是期待它
     */
    private final Sync sync = new Sync();

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}

      这是一个类似于CountDownLatch的闩锁类,除了只需要触发单个 signal 之外。由于闩锁是非排他性的,因此它使用shared获取和释放方法

class BooleanLatch {

    private static class Sync extends AbstractQueuedSynchronizer {
        boolean isSignalled() {
            return getState() != 0;
        }

        @Override
        protected int tryAcquireShared(int ignore) {
            return isSignalled() ? 1 : -1;
        }

        @Override
        protected boolean tryReleaseShared(int ignore) {
            setState(1);
            return true;
        }
    }

    private final Sync sync = new Sync();

    public boolean isSignalled() {
        return sync.isSignalled();
    }

    public void signal() {
        sync.releaseShared(1);
    }

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
}

猜你喜欢

转载自blog.csdn.net/sinat_33472737/article/details/105635875