java AbstractQueuedSynchronizer介绍以及原理分析

来源:互联网 发布:淘宝卖影视资源 编辑:程序博客网 时间:2024/05/29 07:56
简介
提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。
该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础。使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态。然而多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作:

java.util.concurrent.locks.AbstractQueuedSynchronizer.getState()java.util.concurrent.locks.AbstractQueuedSynchronizer.setState(int)java.util.concurrent.locks.AbstractQueuedSynchronizer.compareAndSetState(int, int)


子类推荐被定义为自定义同步装置的内部类,同步器自身没有实现任何同步接口,它仅仅是定义了若干acquire之类的方法来供使用。该同步器即可以作为排他模式也可以作为共享模式,当它被定义为一个排他模式时,其他线程对其的获取就被阻止,而共享模式对于多个线程获取都可以成功。

同步器是实现锁的关键,利用同步器将锁的语义实现,然后在锁的实现中聚合同步器。可以这样理解:锁的API是面向使用者的,它定义了与锁交互的公共行为,而每个锁需要完成特定的操作也是透过这些行为来完成的(比如:可以允许两个线程进行加锁,排除两个以上的线程),但是实现是依托给同步器来完成;同步器面向的是线程访问和资源控制,它定义了线程对资源是否能够获取以及线程的排队等操作。锁和同步器很好的隔离了二者所需要关注的领域,严格意义上讲,同步器可以适用于除了锁以外的其他同步设施上(包括锁)。
同步器的开始提到了其实现依赖于一个FIFO队列,那么队列中的元素Node就是保存着线程引用和线程状态的容器,每个线程对同步器的访问,都可以看做是队列中的一个节点。Node的主要包含以下成员变量:


Node {    int waitStatus;    Node prev;    Node next;    Node nextWaiter;    Thread thread;}

以上五个成员变量主要负责保存该节点的线程引用,同步等待队列(以下简称sync队列)的前驱和后继节点,同时也包括了同步状态。



节点成为sync队列和condition队列构建的基础,在同步器中就包含了sync队列。同步器拥有三个成员变量:sync队列的头结点head、sync队列的尾节点tail和状态state。对于锁的获取,请求形成节点,将其挂载在尾部,而锁资源的转移(释放再获取)是从头部开始向后进行。对于同步器维护的状态state,多个线程对其的获取将会产生一个链式的结构。

一个例子
在上述对同步器AbstractQueuedSynchronizer进行了实现层面的分析之后,我们通过一个例子来加深对同步器的理解:
设计一个同步工具,该工具在同一时刻,只能有两个线程能够并行访问,超过限制的其他线程进入阻塞状态。
对于这个需求,可以利用同步器完成一个这样的设定,定义一个初始状态,为2,一个线程进行获取那么减1,一个线程释放那么加1,状态正确的范围在[0,1,2]三个之间,当在0时,代表再有新的线程对资源进行获取时只能进入阻塞状态(注意在任何时候进行状态变更的时候均需要以CAS作为原子性保障)。由于资源的数量多于1个,同时可以有两个线程占有资源,因此需要实现tryAcquireShared和tryReleaseShared方法,这里谢谢luoyuyou和同事小明指正,已经修改了实现。

public class TwinsLock implements Lock {private final Syncsync= new Sync(2);private static final class Sync extends AbstractQueuedSynchronizer {private static final longserialVersionUID= -7889272986162341211L;Sync(int count) {if (count <= 0) {throw new IllegalArgumentException("count must large than zero.");}setState(count);}public int tryAcquireShared(int reduceCount) {for (;;) {int current = getState();int newCount = current - reduceCount;if (newCount < 0 || compareAndSetState(current, newCount)) {return newCount;}}}public boolean tryReleaseShared(int returnCount) {for (;;) {int current = getState();int newCount = current + returnCount;if (compareAndSetState(current, newCount)) {return true;}}}}public void lock() {sync.acquireShared(1);}public void lockInterruptibly() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public boolean tryLock() {return sync.tryAcquireShared(1) >= 0;}public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(time));}public void unlock() {sync.releaseShared(1);}@Overridepublic Condition newCondition() {return null;}}


测试

public class TwinsLockTest {@Testpublic void test() {final Lock lock = new TwinsLock();class Worker extends Thread {public void run() {while (true) {lock.lock();try {Thread.sleep(1000L);System.out.println(Thread.currentThread());Thread.sleep(1000L);} catch (Exception ex) {} finally {lock.unlock();}}}}for (int i = 0; i &lt; 10; i++) {Worker w = new Worker();w.start();}new Thread() {public void run() {while (true) {try {Thread.sleep(200L);System.out.println();} catch (Exception ex) {}}}}.start();try {Thread.sleep(20000L);} catch (InterruptedException e) {e.printStackTrace();}}}

转自:http://ifeve.com/introduce-abstractqueuedsynchronizer/
  • 大小: 24.4 KB
  • 查看图片附件
0 0
原创粉丝点击