AbstractQueuedSynchronizer document translation

   I. Overview 

        Provide a framework to implement blocking locks and related synchronizers (semaphores, events, etc.) that rely on first-in-first-out (FIFO) waiting queues. This class is intended to provide a useful foundation for most synchronizers that rely on a single atomic int value to represent state. The subclass must define a protected method to change this state, and define what this state means for acquiring or releasing this object. In view of these, other methods in this class will perform all queuing and blocking mechanisms. Subclasses can maintain other state fields, but only to obtain synchronization and only track the use of getState(), setState(int) and compareAndSetState(int, int) methods to manipulate the atomically updated int values.

       The subclass should be defined as a non-public internal helper class used to implement the synchronization properties of the class it is in. AbstractQueuedSynchronizer does not implement any synchronization interface. Instead, it defines methods such as acquireInterruptible, which can be appropriately called through specific locks and related synchronizers to implement its public methods.

        This class supports one of the default exclusive mode and shared mode. When the acquisition is performed exclusively, the acquisitions attempted by other threads will not succeed. The shared mode acquired by multiple threads may (but not necessarily) succeed. This class does not understand these differences, but in a mechanical sense, when the shared mode is successfully acquired, the next waiting thread (if it exists) must also determine whether it can also be acquired. Threads waiting in different modes share the same FIFO queue. Usually, the implementation subclass only supports one of these modes, but both modes can play a role in ReadWriteLock. Subclasses that only support exclusive or shared-only modes do not need to define methods that support unused modes.

       This class defines a nested ConditionObject class, which can be used as a Condition implementation by subclasses that support exclusive mode. IsHeldExclusively reports whether synchronization is reserved exclusively relative to the current thread. Use the current getState value to call the release(int) method to release it completely This object; if given a saved state value, the acquire(int) method can finally restore this object to the state it previously acquired. Otherwise, no other AbstractQueuedSynchronizer method will create such a condition, so if this constraint cannot be met, don't use it. The behavior of AbstractQueuedSynchronizer.ConditionObject of course depends on the semantics of its synchronizer implementation.

       This class provides methods for checking, detecting and monitoring internal queues, as well as similar methods for condition objects. . The AbstractQueuedSynchronizer for its synchronization mechanism can be used to export these methods to the class as needed.

      This type of serialization only stores the basic atomic integer maintenance state, so the deserialized object has an empty thread queue. A typical subclass that requires serializability will define a readObject method that can restore it to a known initial state during deserialization.

Two, usage

        To use this class as the basis of a synchronizer, you need to redefine the following methods appropriately. This is done by using getState(), setState(int) and/or compareAndSetState(int,int) methods to check and/or modify the synchronization state Achieved:

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

       By default, each of these methods will throw UnsupportedOperationException. The implementation of these methods must be thread-safe internally, and should generally be short and non-blocking. Defining these methods is the only supported way of using this class. All other methods are declared as final because they cannot be changed independently.

        You may also find the methods inherited from AbstractOwnableSynchronizer useful for tracking threads that have exclusive synchronizers. You are encouraged to use them, which will enable monitoring and diagnostic tools to help users determine which threads are holding locks.

       Even if this type is based on the internal FIFO queue, it will not automatically execute the FIFO acquisition strategy. The core of exclusive synchronization takes the following form: (The sharing mode is similar, but may involve cascading signals)

  Acquire:

     //Acquire failed
      while (!tryAcquire(arg)) {

         If the thread has not been queued, adding it to the queue
         may block the current thread;
      }
 
  Release:
      if (tryRelease(arg))

          Unblock the first queued thread

 

      Because it is necessary to check the acquisition status of the thread before joining the queue, the new acquisition thread may be inserted before other threads that are blocked and queued. However, if needed, you can define tryAcquire and/or tryAcquireShared to disable insertion by internally calling one or more check methods, thereby providing a fair FIFO acquisition order. In particular, if hasQueuedPredecessors (a method specifically designed for fair synchronizers) returns true, most fair synchronizers can define tryAcquire to return false. Other changes are possible.

       For the default insertion (also known as greedy, renouncement, and convoy-avoidance) strategies, throughput and scalability are usually the highest. Although there is no guarantee that this is fair or unbiased, threads that join the queue earlier are allowed to compete for resources again before the threads that join the queue later, and each thread that participates in contention is compared to the incoming thread. All have equal opportunities for success. In addition, although acquisitions are not "spins" in a general sense, they can perform multiple calls to tryAcquire used by other calculations before blocking. If the exclusive synchronization is only briefly maintained, this provides the greatest benefit for spin, but when this is not the case, it will not bring a lot of burden. If you need to do this, you can use the "fast path" check to call the acquire method first to expand this function. If you may not need to compete for the synchronizer, you can only confirm this by checking hasContended() and/or hasQueuedThreads() in advance. a little.

      By specializing the scope of use of its synchronizer, this class provides an effective and scalable basis for partial synchronization. The synchronizer can rely on int type state, acquire and release parameters, and an internal FIFO waiting queue. When these are not enough, you can use the atomic class, your own custom Queue class, and LockSupport blocking support to build a synchronizer from a lower level.

Three, sample

       This is a non-reentrant mutually exclusive lock class. The value 0 is used to indicate the unlocked state, and the value 1 is used to indicate the locked state. Although non-reentrant locks are not strictly required to record the current owner thread, this class will do so anyway to make usage easier to monitor. It also supports conditions and discloses a detection method

class Mutex implements Lock, java.io.Serializable { 
    
    /** 
     * Internal helper class 
     */ 
    private static class Sync extends AbstractQueuedSynchronizer { 
        // Record whether the lock is held 
        @Override 
        protected boolean isHeldExclusively() { 
            return getState() == 1 ; 
        } 

        // Acquire the lock if the state value is 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 
        } 
    } 

    /** 
     * The synchronization object does all the hard work. We just look forward to it 
     */ 
    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));
    }
}

      This is a latch class similar to CountDownLatch, except that only a single signal needs to be triggered. Since the latch is non-exclusive, it uses shared acquisition and release methods

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

 

 

Guess you like

Origin blog.csdn.net/sinat_33472737/article/details/105635875