JUC - Semaphore 源码分析
来源:互联网 发布:android sql 编辑:程序博客网 时间:2024/05/11 18:07
简介
Semaphore,信号量。用于控制同时访问特定资源的线程数量,来保证合理的使用特定资源。比如:有10个数据库连接,有30个线程都需要使用连接,Semaphore可以控制只有10个线程能够获取连接,其他线程需要排队等待,当已经获取到连接的线程释放连接,排队的线程才能够去申请获取。
源码分析
Semaphore的实现方式是在内部定义了一个实现AbstractQueuedSynchronizer(详见:JUC 源码分析 - AbstractQueuedSynchronizer(AQS))的内部类Sync,Sync主要实现了AbstractQueuedSynchronizer中共享模式的获取和释放方法tryAcquireShared和tryReleaseShared,在Semaphore中使用AQS的子类Sync,初始化的state表示许可数,在每一次请求acquire()一个许可都会导致state减少1,同样每次释放一个许可release()都会导致state增加1。一旦达到了0,新的许可请求线程将被挂起,直到有许可被释放。
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 1192457210091910933L; Sync(int permits) {//Sync的构造方法初始化可用许可数量 setState(permits); } final int getPermits() { return getState();//state代表当前总共可用许可数量 } final int nonfairTryAcquireShared(int acquires) {//非公平的获取许可,代表新插入的线程,可以和同步队列中的节点竞争获取锁 for (;;) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } protected final boolean tryReleaseShared(int releases) {//释放许可,每次释放,通过循环和CAS保证并发时也可以安全的释放 for (;;) { int current = getState(); int next = current + releases; if (next < current) // overflow throw new Error("Maximum permit count exceeded"); if (compareAndSetState(current, next)) return true; } } final void reducePermits(int reductions) {//减少一定数量的许可 for (;;) { int current = getState(); int next = current - reductions; if (next > current) // underflow throw new Error("Permit count underflow"); if (compareAndSetState(current, next)) return; } } final int drainPermits() {//清空可用许可 for (;;) { int current = getState(); if (current == 0 || compareAndSetState(current, 0)) return current; } } }
公平与非公平的实现,主要区别就是在获取许可时,公平实现会检查同步队列是否有线程处在等待,有则获取失败进入同步队列中去等待,非公平实现则不会检查,新插入的线程可以和队列中等待最久的线程一起竞争锁的使用,非公平是默认的实现,因为减少了线程挂起和释放,线程上下文切换的开销,性能好,缺点是有可能造成锁饥饿,队列中的线程迟迟无法获取到锁。
static final class NonfairSync extends Sync {//非公平 private static final long serialVersionUID = -2694183684443567898L; NonfairSync(int permits) { super(permits); } protected int tryAcquireShared(int acquires) { return nonfairTryAcquireShared(acquires); } } final int nonfairTryAcquireShared(int acquires) { for (;;) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } }
static final class FairSync extends Sync {//公平 private static final long serialVersionUID = 2014338818796000944L; FairSync(int permits) { super(permits); } protected int tryAcquireShared(int acquires) { for (;;) { if (hasQueuedPredecessors())//检查同步队列中是否有等待的节点 return -1; int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } } public final boolean hasQueuedPredecessors() { Node t = tail; Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
使用方式
public class SemaphoreTest { public static void main(String[] args) { final Semaphore semaphore = new Semaphore(2); ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { executorService.execute(new Runnable() { public void run() { try { semaphore.acquire(); try { System.out.println("线程:" + Thread.currentThread().getName() + "获得许可"); TimeUnit.SECONDS.sleep(1);//访问特定资源 } finally { semaphore.release(); System.out.println("剩余许可:" + semaphore.availablePermits()); } } catch (InterruptedException e) { e.printStackTrace(); } } }); } executorService.shutdown(); }}
0 0
- JUC - Semaphore 源码分析
- JUC源码分析11-locks-Semaphore
- Java多线程 -- JUC包源码分析9 -- AbstractQueuedSynchronizer深入分析-- Semaphore与CountDownLatch
- JUC - CountDownLatch 源码分析
- JUC - ReentrantLock 源码分析
- JUC - Condition 源码分析
- JUC - ReentrantReadWriteLock 源码分析
- JUC - ThreadPoolExecutor 源码分析
- JUC - FutureTask 源码分析
- 《Java源码分析》:Semaphore
- Semaphore 源码分析
- 《Java源码分析》:Semaphore
- JUC - AbstractQueuedSynchronizer(AQS) 源码分析
- 源码分析之JUC-Exchanger
- Java 并发 --- Semaphore源码分析
- JUC源码分析5-locks-LockSupport
- JUC源码分析8-locks-AQS-condition
- JUC源码分析9-locks-ReentrantLock
- ATP-GET常用操作
- Hough直线检测和圆检测
- TOTALCMD 小计
- DOS,WINDOWS递归删除指定文件夹或文件
- 成员函数或友元函数做为线程函数
- JUC - Semaphore 源码分析
- EXEC族
- C++ 两个类互相引用
- 设计模式——观察者模式
- SPICE:独立计算环境的简单协议
- Unity导出android工程集成到android studio项目内
- 红帽Spice 入门
- 时间友好型提示风格化(即微博中的XXX小时前、昨天等等)
- VDI(Virtual Desktop Infrastructure)