java中的锁——列队同步器

Posted 谁为含愁独不见,更教明月照流黄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中的锁——列队同步器相关的知识,希望对你有一定的参考价值。

队列同步器

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

队列同步器的使用

1: Protected 类别:

AbstractQueuedSynchornizer是抽象类,但是没有一个抽象方法。AbstractQueuedSynchornizer虽然没有抽象方法,但是提供了五个方法可以让我们在子类中重载,并且这五个方法都是空的实现且直接抛出异常,也就是说我们要使用这五个方法所提供的功能,必须在子类中自己实现,这也是模板方法模式的一种体现和使用。(为了将此类用作同步器的基础,需要适当地重新定义以下方法,这是通过使用 getState()setState(int) 和/或 compareAndSetState(int, int) 方法来检查和/或修改同步状态来实现的:)

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类别:

另外还有三个:hasWaiters、getWaitQueueLength、getWaitingThreads三个方法。

同步列队

队列同步器的实现依赖内部的同步队列来完成同步状态的管理。它是一个FIFO的双向队列,当线程获取同步状态失败时,同步器会将当前线程和等待状态等信息包装成一个节点并将其加入同步队列,同时会阻塞当前线程。当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态。

节点是构成同步队列的基础,同步器拥有首节点和尾节点,没有成功获取同步状态的线程会成为节点加入该队列的尾部

 

同步器包含了两个节点类型的引用,一个指向头节点,而另一个指向尾节点。

 

如果一个线程没有获得同步队列,那么包装它的节点将被加入到队尾,显然这个过程应该是线程安全的。因此同步器提供了一个基于CAS的设置尾节点的方法:compareAndSetTail(Node expect,Node update),它需要传递一个它认为的尾节点和当前节点,只有设置成功,当前节点才被加入队尾
 
同步队列遵循FIFO(先进先出),首节点是获取同步状态成功的节点,首节点线程在释放同步状态时,将会唤醒后继节点,而后继节点将会在获取同步状态成功时将自己设置为首节点

......

以上是关于java中的锁——列队同步器的主要内容,如果未能解决你的问题,请参考以下文章

Java中的锁

《Java并发编程的艺术》读后笔记-第五章 Java中的锁

《Java并发编程的艺术》--Java中的锁

Java并发编程 JUC中的锁

java中ReentrantReadWriteLock读写锁的使用

死磕 java同步系列之开篇