Semaphore
Semaphore,俗称信号量,就类似于互斥锁,通过同时只能有一个线程获取信号量实现。大小为n(n>0)的信号量可以实现限流的功能,它可以实现只能有n个线程同时获取信号量。
PV操作是操作系统一种实现进程互斥与同步的有效方法
PV操作与信号量(S)的处理相关,P表示通过的意思,V表示释放的意思。用PV操作来管理共享资源时,首先要确保PV操作自身执行的正确性。
- P操作的主要动作是:
- S减1;
- 若S减1后仍大于或等于0,则进程继续执行
- 若S减1后小于0,则该进程被阻塞后放入等待该信号量的等待队列中,然后转进程调度
- V操作的主要动作是:
- S加1;
- 若相加后结果大于0,则进程继续执行;
- 若相加后结果小于或等于0,则从该信号的等待队列中释放一个等待进程,然后再返回原进程继续执行或转进程调度。
Semaphore流程
Semaphore window = new Semaphore(3),初始化的是非公平锁,信号量3是指是赋值给state。
public static void main(String[] args) throws InterruptedException {//资源,3个窗口Semaphore window = new Semaphore(3);for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {try {//占用窗口,加锁window.acquire();System.out.println(Thread.currentThread().getName() + "开始买票");//模拟买票流程Thread.sleep(5000);System.out.println(Thread.currentThread().getName() + "买票成功");} catch (Exception e) {e.printStackTrace();} finally {window.release();}}}).start();}}
Thread0
- 调用acquire是指调用acquireSharedInterruptibly,执行tryAcquireShared(arg),arg=1

- tryAcquireShared,最终调用nonfairTryAcquireShared方法

- 此时thread0获得锁成功,把status修改为2
Thread1
- thread1执行thread0一样的操作,cas成功,把state修改为1
Thread2
- thread2执行thread1一样的操作,cas成功,把state修改为0
Thread3
- thread3执行thread2一样的流程,因为此时的remaining已经小于0了
- 然后执行doAcquireSharedInterruptibly方法

- 调用shouldParkAfterFailedAcquire,返回false

- 然后开始第二轮循环,继续执行shouldParkAfterFailedAcquire,此时是返回true,然后执行parkAndCheckInterrupt

- 把thread3挂起
Thread4
- thread4和thread一样的流程,同样被挂起。
- 此时的等待队列是:

解锁release
- release,最终调用releaseShared方法,arg=1。releaseShared调用tryReleaseShared


- 就是通过cas把state更新,把state加上releases,就相当于把资源放回去,此时的state=1。
- 然后执行doReleaseShared

- 此时的头节点的waitState是-1,然后进行cas,先把头节点的waitState修改为0,然后执行unparkSuccessor

- 此时的thread3被唤醒,再去争抢锁,此时cas的tryAcquireShared会成功

- 然后执行setHeadAndPropagate

- doReleaseShared,做的东西就是把head节点的next节点(thread4)去唤醒。例如唤醒了thred4后,还有next节点的话,也会继续去唤醒下一个。

�
