Board logo

标题: Java并发编程-AbstractQueuedSynchronizer源码分析(10) [打印本页]

作者: look_w    时间: 2019-1-17 19:28     标题: Java并发编程-AbstractQueuedSynchronizer源码分析(10)

public final boolean releaseShared(int arg)调用该方法释放共享状态,每次获取共享状态acquireShared都会操作状态,同样在共享锁释放的时候,也需要将状态释放。比如说,一个限定一定数量访问的同步工具,每次获取都是共享的,但是如果超过了一定的数量,将会阻塞后续的获取操作,只有当之前获取的消费者将状态释放才可以使阻塞的获取操作得以运行。



上述逻辑主要就是调用同步器的tryReleaseShared方法来释放状态,并同时在doReleaseShared方法中唤醒其后继节点。
一个例子在上述对同步器AbstractQueuedSynchronizer进行了实现层面的分析之后,我们通过一个例子来加深对同步器的理解:
设计一个同步工具,该工具在同一时刻,只能有两个线程能够并行访问,超过限制的其他线程进入阻塞状态。
对于这个需求,可以利用同步器完成一个这样的设定,定义一个初始状态,为2,一个线程进行获取那么减1,一个线程释放那么加1,状态正确的范围在[0,1,2]三个之间,当在0时,代表再有新的线程对资源进行获取时只能进入阻塞状态(注意在任何时候进行状态变更的时候均需要以CAS作为原子性保障)。由于资源的数量多于1个,同时可以有两个线程占有资源,因此需要实现tryAcquireShared和tryReleaseShared方法,这里谢谢luoyuyou和同事小明指正,已经修改了实现。
[url=][/url]
01    public class TwinsLock implements Lock {02        private final Sync  sync    = new Sync(2);03     04        private static final class Sync extends AbstractQueuedSynchronizer {05            private static final long   serialVersionUID    = -7889272986162341211L;06     07            Sync(int count) {08                if (count <= 0) {09                    throw new IllegalArgumentException("count must large than zero.");10                }11                setState(count);12            }13     14            public int tryAcquireShared(int reduceCount) {15                for (;;) {16                    int current = getState();17                    int newCount = current - reduceCount;18                    if (newCount < 0 || compareAndSetState(current, newCount)) {19                        return newCount;20                    }21                }22            }23     24            public boolean tryReleaseShared(int returnCount) {25                for (;;) {26                    int current = getState();27                    int newCount = current + returnCount;28                    if (compareAndSetState(current, newCount)) {29                        return true;30                    }31                }32            }33        }34     35        public void lock() {36            sync.acquireShared(1);37        }38     39        public void lockInterruptibly() throws InterruptedException {40            sync.acquireSharedInterruptibly(1);41        }42     43        public boolean tryLock() {44            return sync.tryAcquireShared(1) >= 0;45        }46     47        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {48            return sync.tryAcquireSharedNanos(1, unit.toNanos(time));49        }50     51        public void unlock() {52            sync.releaseShared(1);53        }54     55        @Override56        public Condition newCondition() {57            return null;58        }59    }[url=][/url]





这里我们编写一个测试来验证TwinsLock是否能够正常工作并达到预期。
[url=][/url]
01    public class TwinsLockTest {02     03        @Test04        public void test() {05            final Lock lock = new TwinsLock();06     07            class Worker extends Thread {08                public void run() {09                    while (true) {10                        lock.lock();11     12                        try {13                            Thread.sleep(1000L);14                    System.out.println(Thread.currentThread());15                            Thread.sleep(1000L);16                        } catch (Exception ex) {17     18                        } finally {19                            lock.unlock();20                        }21                    }22                }23            }24     25            for (int i = 0; i &lt; 10; i++) {26                Worker w = new Worker();27                w.start();28            }29     30            new Thread() {31                public void run() {32                    while (true) {33     34                        try {35                            Thread.sleep(200L);36                            System.out.println();37                        } catch (Exception ex) {38     39                        }40                    }41                }42            }.start();43     44            try {45                Thread.sleep(20000L);46            } catch (InterruptedException e) {47                e.printStackTrace();48            }49        }50    }[url=][/url]




上述测试用例的逻辑主要包括:
​1. 打印线程
Worker在两次睡眠之间打印自身线程,如果一个时刻只能有两个线程同时访问,那么打印出来的内容将是成对出现。
​2. 分隔线程
不停的打印换行,能让Worker的输出看起来更加直观。
该测试的结果是在一个时刻,仅有两个线程能够获得到锁,并完成打印,而表象就是打印的内容成对出现。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0