队列同步器
队列同步器(AbstractQueuedSynchronizer)为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()
、setState(int)
和 compareAndSetState(int, int)
方法来操作以原子方式更新的 int 值。
队列同步器的使用
1: Protected 类别:
AbstractQueuedSynchornizer是抽象类,但是没有一个抽象方法。AbstractQueuedSynchornizer虽然没有抽象方法,但是提供了五个方法可以让我们在子类中重载,并且这五个方法都是空的实现且直接抛出异常,也就是说我们要使用这五个方法所提供的功能,必须在子类中自己实现,这也是模板方法模式的一种体现和使用。(为了将此类用作同步器的基础,需要适当地重新定义以下方法,这是通过使用 getState()
、setState(int)
和/或 compareAndSetState(int, int)
方法来检查和/或修改同步状态来实现的:)
tryAcquire(int)
//试图在独占模式下获取对象状态。tryRelease(int)
//试图设置状态来反映独占模式下的一个释放。tryAcquireShared(int)
//试图在共享模式下获取对象状态。tryReleaseShared(int)
//试图设置状态来反映共享模式下的一个释放isHeldExclusively()
//如果对于当前(正调用的)线程,同步是以独占方式进行的,则返回true
。
2:public final类别
除了上述protected的方法之外,还有一个关键的类别就是public final,这是我们可以直接使用的方法,称之为模板方法,当我们实现自定义的同步组件的时候,我们可以调用这些模板方法获取我们需要的东西。
(1) Void acquire(int arg) //独占式获取同步状态,如果当前线程获取同步状态成功,则由该方法返回,否则,将进入同步队列等待,该方法将会调用重写的tryAcquire(int arg) 方法
(2) Void acquireInterruptibly(int arg) //与acquire相同,但是该方法会响应中断,当前线程未获取到同步状态而进入同步队列中,如果当前线程被中断,则该方法会抛出InteruptedException并返回
(3) Boolean tryAcquireNanos(int arg,long nanos) //在acquireInterruptibly(int arg )的基础上增加了超时限制 如果当前线程在超时时间内没有获取到同步状态,那么将会返回false,如果获取到了返回为true
(4) Void acquireShared(int arg) //共享式的获取同步状态,如果当前线程为获取到同步状态,将会进入同步队列等待,与独占式获取的主要区别是在同一时刻可以有多个线程获取到同步状态。
(5) Void acquireSharedInterruptibly(int args) //与acquireShared(int arg)相同,该方法响应中断
(6)boolean tryAcquireSharedNanos(int arg,long nanos) //在acquireShared(int arg) 基础上增加了超时限制
(7) boolean release(int arg) //独占式的释放同步状态,该方法会在释放同步状态之后,将同步队列
(8) boolean releaseShared(int arg) // 共享式的释放同步状态
(9) Collection<Thread> getQueuedThreads() //获取等待在同步队列上的线程集合。
3: Protected fianl类别:
getState()
//返回同步状态的当前值。setState(int)
//设置同步状态的值。compareAndSetState(int, int)
//如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。
另外还有三个:hasWaiters、getWaitQueueLength、getWaitingThreads三个方法。
同步列队
队列同步器的实现依赖内部的同步队列来完成同步状态的管理。它是一个FIFO的双向队列,当线程获取同步状态失败时,同步器会将当前线程和等待状态等信息包装成一个节点并将其加入同步队列,同时会阻塞当前线程。当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态。
节点是构成同步队列的基础,同步器拥有首节点和尾节点,没有成功获取同步状态的线程会成为节点加入该队列的尾部
......