体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(7)
来源:互联网 发布:怎么让访客网络不影响 编辑:程序博客网 时间:2024/06/05 20:07
/* * ---------------------------------------------------- * 使用LockSupport来实现可重入的信号(前面实现的都不是可重入的) * 除了共享数据本身的原子性、一致性、隔离性的考虑之外 * 作为某种锁的存在的对象常还要考虑中断和重入 * 中断的情况最开始的测试代码中有提到,需要根据具体的情况来考虑如何处理。 * 而重入则是重复对某个带锁方法的调用,有的时候是有意的,有时则是误调用,都需要引起注意。 * ---------------------------------------------------- */class ReentrantSema implements IMySemaphore { private AtomicInteger _iSignal; private final int _iPermits; private Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread> (); // 对于并发线程重入次数需要记录 private ConcurrentHashMap<Thread, Integer> runningThread = new ConcurrentHashMap<Thread, Integer> (); ReentrantSema(final int i) { _iSignal = new AtomicInteger(0); _iPermits = i; } public void acquire() throws InterruptedException { Thread current = Thread.currentThread(); // 判断是否已得到信号量 Integer cnt = runningThread.get(current); if (cnt != null) { if (Thread.interrupted()) { throw new InterruptedException(); } runningThread.put(current, new Integer(cnt + 1)); return; } boolean wasInterrupted = false; waiters.add(current); int i, update; while (true) { i = _iSignal.get(); if (waiters.peek() != current || (!wasInterrupted && (i >= _iPermits))) { // 申请条件不够 LockSupport.park(this); if (Thread.interrupted()) { wasInterrupted = true; continue; } } if (wasInterrupted) { break; } if (i >= _iPermits) { continue; } // 利用 AtomicInteger 的 CAS 操作确保申请到信号量 update = i + 1; if (waiters.peek() == current && _iSignal.compareAndSet(i, update)) { // get the lock runningThread.put(current, new Integer(1)); break; } } // 唤醒下一个等待线程 waiters.remove(); LockSupport.unpark(waiters.peek()); if (wasInterrupted) { throw new InterruptedException(); } } public void release() { Thread current = Thread.currentThread(); Integer cnt = runningThread.get(current); assert (cnt != null); // 释放信号时要注意可能只是从某个层次退出 // 完全退出后才能真正释放 if (cnt == 1) { runningThread.remove(current); _iSignal.decrementAndGet(); LockSupport.unpark(waiters.peek()); } else { runningThread.put(current, new Integer(cnt - 1)); } }} // END: ReentrantSema/** * 带重入方法的 Worker, 会多次调用 acquire 方法 */class ReentrantWorker implements Runnable { private final int _id; private final long _wait; private final IMySemaphore _semaphore; private final long _lCreateTime; private static void println(final String msg) { System.out.println(msg); } ReentrantWorker(final int id, final IMySemaphore semaphore, final long now) { _id = id; _wait = (10 - _id) * 1000; _semaphore = semaphore; _lCreateTime = now; } public void run() { try { // 第一次申请 _semaphore.acquire(); try { println(String.format("Worker[%d] is running...", _id)); // 重入,子类中很可能会误调用某个已经申请了信号量的方法 // 如果信号量不支持重入,就可能引起死锁 reentrant(); long period = (System.currentTimeMillis() - _lCreateTime) / 1000; println(String.format("Worker[%d] is end, %d seconds after created.", _id, period)); } catch (InterruptedException ie) { // swap exception to somewhere // report and stop this thread } finally { // 释放 _semaphore.release(); } } catch (InterruptedException ie) { // 申请时被中断 long period = (System.currentTimeMillis() - _lCreateTime) / 1000; println(String.format("Worker[%d] is interrupted, %d seconds after created.", _id, period)); return; } } private void reentrant() throws InterruptedException { try { // 申请 _semaphore.acquire(); try { long begin = System.currentTimeMillis(); println(String.format("Worker[%d] reentrant success...", _id)); // 又重入一次 reentrant2(); long period = (System.currentTimeMillis() - begin) / 1000; println(String.format("Worker[%d] reentrant end, %d seconds after created.", _id, period)); } catch (InterruptedException ie) { throw ie; } finally { // 释放 _semaphore.release(); } } catch (InterruptedException ie) { // 申请被中断 throw ie; } } private void reentrant2() throws InterruptedException { try { // 申请 _semaphore.acquire(); try { long begin = System.currentTimeMillis(); println(String.format("Worker[%d] reentrant 2 success...", _id)); Thread.currentThread().sleep(_wait); long period = (System.currentTimeMillis() - begin) / 1000; println(String.format("Worker[%d] reentrant 2 end, %d seconds after created.", _id, period)); } catch (InterruptedException ie) { throw ie; } finally { // 释放 _semaphore.release(); } } catch (InterruptedException ie) { // 申请被中断 throw ie; } }} // END: ReentrantWorker
还有更多的方法可以继续体验……
0 0
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(7)
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(1)
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(2)
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(3)
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(4)
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(5)
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(6)
- JAVA并发信号量 Semaphore
- java并发信号量Semaphore
- java并发之Semaphore(计数信号量)
- java并发之Semaphore(信号量)
- java 并发工具包 -信号量 Semaphore
- Java并发编程实战--计数信号量(Semaphore)
- Java并发编程——Semaphore (信号量)和CountDownLatch
- Java多线程/并发22、信号量Semaphore
- Java并发包之Semaphore信号量
- 并发中的信号量Semaphore
- 【Java并发编程】之二十三:并发新特性—信号量Semaphore(含代码)
- Win7旗舰版中的IIS配置asp.net的运行环境
- 自绘CComboBox
- linux如何查看命令对于的是哪个软件包&linux排错思路
- 线性表的查找(顺序查找,二分查找,分块查找)
- setContentView(R.layout.XXXXX) 没设置到 就开始 initViews() 会导致空指针
- 体验 Java 并发 api,用不同方式实现信号量锁(Semaphore)(7)
- input
- HYSBZ/BZOJ 1011 [HNOI2008] 遥远的行星 - 模糊答案&暴力
- 系统间的接口联调测试
- Android进阶推荐书籍
- Bitmap.recycle引发的血案
- Redis学习手册(Sorted-Sets数据类型)
- 评估AWS EC2作为web server时的网络负载
- hash算法 (hashmap 实现原理)