码迷,mamicode.com
首页 > 其他好文 > 详细

Semaphore信号量原理

时间:2020-07-04 18:45:22      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:thread   release   new   log   核心   detail   自旋   port   details   

Semaphore信号量原理

  • Semaphore是一个计数信号量,本质是"共享锁".
  • Semaphore维护一个信号量许可集.
  • 线程可以调用acquire()获得信号量的许可.
  • 线程可以调用release()释放其持有的信号量.
  • 使用acquire()请求获得信号量时,若信号量有可用的许可时,线程获得许可,并且当前可用的许可减1.若许可集已经分配完,则线程进入等待状态,直到其他线程释放许可才有机会再获得许可.
  • 使用release()释放信号量时,当前可用的信号量加1.
  • new Semaphore(int permits)设置初始的许可数.
  • acquire(int permits)获取指定数量的许可,若获取成功,则执行,否则线程阻塞等待条件满足.
  • acquire(0),表明不需要获得许可即可继续执行.若后续使用release(),则信号量的总许可数加1.
  • 若初始化许可设为0,则使用acquire(0)可继续执行,若使用acquire()或请求正整数个许可,则线程一直处于请求状态.

Semaphore函数列表

Semaphore(int permits) // 给定许可数量的非公平信号量
Semaphore(int permits, boolean fair) // 给定许可数量,设置公平的信号量

void acquire() // 从信号量中获得一个许可,若不足,则线程阻塞
void acquire(int permits) // 获得指定数量的许可

int availablePermits() // 获得当前可用的许可数

int drainPermits() // 摧毁剩下的许可

protected Collection<Thread> getQueuedThreads() // 返回等待获取的线程

内部类

Semaphore有一个基于AQS的内部类Sync.基于这个类,分别实现了公平模式(FairSync)和非公平模式(NonFairSync).

若初始化为1,则最多只有一个可用的许可证,可作为互斥锁使用,被称为二进制信号量.
其只有两个状态:
* 允许可用.
* 不允许可用
不同于锁,二进制信号量可以由持有者以外的线程释放.(可用于死锁恢复)

非公平模式
不保证线程获取许可的顺序.
一个调用acquire()的线程可能先于等待很久的线程获得许可.(将新线程放在等待队列头)

公平模式
保证获得许可的顺序为线程调用acquire()方法的顺序.中

实现原理

内部类Sync继承于AQS(维护同步队列,控制同步状态).
实现两种锁:

  • 公平锁(FairSync)
  • 非公平锁(NoFairSync)

默认构造的为非公平锁.

核心方法

acquire()

  1. 若state值代表的许可数足够使用,则请求的线程将获得同步状态(对共享资源的访问权,并更新state值)
  2. 若state代表的许可数为0,则请求的线程无法获得同步状态,线程被加入到同步队列中并阻塞,直到其他线程释放同步状态才能获得对共享资源的访问.

细节:

  • 是可中断的.先检查线程的中断情况.若有中断,则抛出异常.若没有中断,则尝试获取同步状态.
  • 获取方式:先获取状态state,再对状态进行减法操作,并使用CAS保证对state状态的修改的安全性.
  • 进入队列的操作:当前线程自旋操作:判断前驱节点是否为head节点.若是,则获取同步状态.获取成功,则将当前节点设为head节点,并向后传播(同步状态剩余值大于0,通知后续节点继续获取同步状态)

注:

  • 对于不可中断的,少了中断的判断以及异常的抛出.

release()

  • 调用AQS中的方法尝试CAS释放同步状态.若释放成功,则唤醒同步队列中后继节点的线程.
  • 释放细节:获得当前状态,然后采用CAS方式更新state.
  • 唤醒后继节点的细节:
    • 获取head节点的状态,若为SIGNAL,则后继节点需要被唤醒.若head节点的后继结点为空或不可唤醒,则从队列尾端向前查找最靠前的可唤醒的节点进行唤醒.(LockSupport的unpark()方法)

公平锁

  • 与非公平锁的不同在于:在尝试获取同步状态时,先判断同步队列中是否存在节点.若存在,则将线程加入到同步等待队列中,从而保证先到的线程一定先执行.

小结

  • 通过AQS对状态值state进行控制,从而控制并发访问资源的线程数.
  • 线程在成功获取资源后,状态值state会减一.
  • 若超过限制的线程请求资源,则线程会加入等待队列中,直到其他线程执行释放同步状态,才有机会获得访问权.
  • 每个线程在释放同步状态后,状态值state会加1.

参考:

Semaphore信号量原理

标签:thread   release   new   log   核心   detail   自旋   port   details   

原文地址:https://www.cnblogs.com/truestoriesavici01/p/13235985.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!