创建 Semaphore 实例的时候,需要一个参数 permits,
这个基本上可以确定是设置给 AQS 的 state 的,
然后每个线程调用 acquire 的时候,执行 state = state - 1,
release 的时候执行 state = state + 1,
当然,acquire 的时候,如果 state = 0,说明没有资源了,需要等待其他线程 release。
基本操作
1.创建Semaphore对象,初始化permits
2. semaphore.acquire() 占用一个位置
3. semaphore.release() 取消一个位置
Semaphore原理是AQS 可以理解成 就是多个对象共持有的一把锁,达到permits数量 再想争抢锁就要等待,持有锁的对象释放。也区分公平锁非公平锁竞争原则
源码解析:
1. new Semaphore()
没啥好说的 初始化设置AQS的state
2. acquire(int permits) 占用几个空位的资源
acquireSharedInterruptibly() 老中断处理了
if (tryAcquireShared(arg) < 0) //说明占位失败 要么是没那么多位置给你占 要么是CAS失败了
3. tryAcquireShared() 非公平锁的实现
死循环(){
获取当前的state值;
remaining = state - 想要占位数;
if(如果想要占位数>state总数 或者CAS成功 ){
返回剩余位数;
}
}
4. doAcquireSharedInterruptibly() 占位失败,加入到阻塞队列
将节点封装成Node 加入到阻塞队列
for( 死循环){
判断前直接点是不是头节点;
如果前置节点是头节点,尝试去抢占位置,
抢占成功了,大吉大利 队列中删除节点,结束;
抢失败了 挂起等待唤醒。
}
finally{
如果中途被中断了 就退出争抢 不玩了;
}
5. relase() 释放资源
6. tryReleaseShared() 尝试释放共享资源 改state值
for(死循环){
获取当前state值;
next = state + 要释放的位置数;
CAS交换
}
7. doReleaseShared() 唤醒所有等待的节点