再看AbstractQueuedSynchronizer

版权声明: https://blog.csdn.net/Dongguabai/article/details/84178241

相关博客:

https://blog.csdn.net/Dongguabai/article/details/82691626

https://blog.csdn.net/Dongguabai/article/details/82461675

主要对之前的学习进行一个补充。

AbstractQueuedSynchronizer是实现同步容器的基础。在JUC中是一个非常主要的类,JDK文档是这么描述的:

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

 有这么几个重点:
1.FIFO;

2.依靠单个原子int值来表示状态;

    

3.子类必须定义更改此状态的受保护方法;

4.基于模板;

在如何使用还有这样一段描述:

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

默认情况下,每个方法都抛出 UnsupportedOperationException。这些方法的实现在内部必须是线程安全的,通常应该很短并且不被阻塞。定义这些方法是使用此类的 唯一受支持的方式。其他所有方法都被声明为 final,因为它们无法是各不相同的。

 也就是说只有5个方法我们可以自己定义,其它的方法均为final。独占式使用tryAcquire(int)和tryRelease(int),共享式使用tryAcquireShared(int)和tryReleaseShared(int)。

API如下:

方法摘要
 void acquire(int arg) 
          以独占模式获取对象,忽略中断。
 void acquireInterruptibly(int arg) 
          以独占模式获取对象,如果被中断则中止。
 void acquireShared(int arg) 
          以共享模式获取对象,忽略中断。
 void acquireSharedInterruptibly(int arg) 
          以共享模式获取对象,如果被中断则中止。
protected  boolean compareAndSetState(int expect, int update) 
          如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。
 Collection<Thread> getExclusiveQueuedThreads() 
          返回包含可能正以独占模式等待获取的线程 collection。
 Thread getFirstQueuedThread() 
          返回队列中第一个(等待时间最长的)线程,如果目前没有将任何线程加入队列,则返回 null. 在此实现中,该操作是以固定时间返回的,但是,如果其他线程目前正在并发修改该队列,则可能出现循环争用。
 Collection<Thread> getQueuedThreads() 
          返回包含可能正在等待获取的线程 collection。
 int getQueueLength() 
          返回等待获取的线程数估计值。
 Collection<Thread> getSharedQueuedThreads() 
          返回包含可能正以共享模式等待获取的线程 collection。
protected  int getState() 
          返回同步状态的当前值。
 Collection<Thread> getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition) 
          返回一个 collection,其中包含可能正在等待与此同步器有关的给定条件的那些线程。
 int getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition) 
          返回正在等待与此同步器有关的给定条件的线程数估计值。
 boolean hasContended() 
          查询是否其他线程也曾争着获取此同步器;也就是说,是否某个 acquire 方法已经阻塞。
 boolean hasQueuedThreads() 
          查询是否有正在等待获取的任何线程。
 boolean hasWaiters(AbstractQueuedSynchronizer.ConditionObject condition) 
          查询是否有线程正在等待给定的、与此同步器相关的条件。
protected  boolean isHeldExclusively() 
          如果对于当前(正调用的)线程,同步是以独占方式进行的,则返回 true
 boolean isQueued(Thread thread) 
          如果给定线程的当前已加入队列,则返回 true。
 boolean owns(AbstractQueuedSynchronizer.ConditionObject condition) 
          查询给定的 ConditionObject 是否使用了此同步器作为其锁。
 boolean release(int arg) 
          以独占模式释放对象。
 boolean releaseShared(int arg) 
          以共享模式释放对象。
protected  void setState(int newState) 
          设置同步状态的值。
 String toString() 
          返回标识此同步器及其状态的字符串。
protected  boolean tryAcquire(int arg) 
          试图在独占模式下获取对象状态。
 boolean tryAcquireNanos(int arg, long nanosTimeout) 
          试图以独占模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。
protected  int tryAcquireShared(int arg) 
          试图在共享模式下获取对象状态。
 boolean tryAcquireSharedNanos(int arg, long nanosTimeout) 
          试图以共享模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。
protected  boolean tryRelease(int arg) 
          试图设置状态来反映独占模式下的一个释放。
protected  boolean tryReleaseShared(int arg) 
          试图设置状态来反映共享模式下的一个释放。

 ReentrantLock就是基于AQS实现的,可以看看ReentrantLock的lokc()方法:

这个方法交给了同步器去处理,看看这个同步器:

继承了AQS,而且lock()方法还是abstact的。这是因为ReentrantLock有公平和非公平两种情况:

下面来看看NonfairSync中的lock()方法:

使用CAS设置当前状态,设置当前线程为独占线程。重点看这个acquire()方法。这个acquire()方法其实是AQS中的方法:

acquire()方法是这么描述的:

acquire

public final void acquire(int arg)

以独占模式获取对象,忽略中断。通过至少调用一次 tryAcquire(int) 来实现此方法,并在成功时返回。否则在成功之前,一直调用 tryAcquire(int) 将线程加入队列,线程可能重复被阻塞或不被阻塞。可以使用此方法来实现 Lock.lock() 方法。

参数:

arg - acquire 参数。此值被传送给 tryAcquire(int),但它是不间断的,并且可以表示任何内容。

 这是一个final方法,而在AQS中acquire()内部调用了tryAcquire()方法,上面也介绍过了,tryAcquire()方法需要被重写。看看实现的tryAcquire()方法:

 /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            //获取当前线程
            final Thread current = Thread.currentThread();
            //获取状态
            int c = getState();
            if (c == 0) {
                //判断当前线程是否获取到锁
                if (compareAndSetState(0, acquires)) {
                    //设置为当前线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
             //如果是当前线程开始判断重入
            else if (current == getExclusiveOwnerThread()) {
                //状态加
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                 //更新状态
                setState(nextc);
                 //获取成功
                return true;
            }
            return false;
        }

反过来再看acquire()方法,如果获取不成功就要执行acquireQueued(addWaiter(Node.EXCLUSIVE),arg))方法。之前也介绍过,内部会维护一个FIFO,这个方法就是放进等待队列里面。看看AQS中的addWaiter(Node node)方法:

再看看acquireQueued()方法,刚刚直接将节点插入到了等待队列中,但是当前线程还没有被阻塞(具体可参看:https://blog.csdn.net/Dongguabai/article/details/82461675)。

猜你喜欢

转载自blog.csdn.net/Dongguabai/article/details/84178241