Semaphore共享锁

简介

在多线程环境下用于协调各个线程, 以保证它们能够正确、合理的使用公共资源
信号量维护了一个许可集,我们在初始化Semaphore时需要为这个许可集传入一个数量值,
该数量值代表同一时间能访问共享资源的线程数量。
线程可以通过acquire()方法获取到一个许可,然后对共享资源进行操作,
如果许可集已分配完了,那么线程将进入等待状态,
直到其他线程释放许可才有机会再获取许可,线程释放一个许可通过release()方法完成

DEMO了解其用法

上述示例说明:在创建Semaphore时初始化5个许可,这也就意味着同一个时间点允许5个线程进行共享资源访问,
使用acquire()方法为每个线程获取许可,并进行休眠1秒,如果5个许可已被分配完,
新到来的线程将进入等待状态。如果线程顺利完成操作将通过release()方法释放许可,
我们执行代码,可以发现每隔1秒几乎同一时间出现5条线程访问

Semaphore实现互斥锁

简介

在初始化信号量时传入1,使得它在使用时最多只有一个可用的许可,从而可用作一个相互排斥的锁。
这通常也称为二进制信号量,因为它只能有两种状态:一个可用的许可或零个可用的许可。
按此方式使用时,二进制信号量具有某种属性(与很多 Lock 实现不同),即可以由线程释放“锁”,而不是由所有者(因为信号量没有所有权的概念)

DEMO了解其用法

创建一个数量为1的互斥信号量Semaphore,
然后并发执行10个线程,在线程中利用Semaphore控制线程的并发执行,
因为信号量数值只有1,因此每次只能一条线程执行,其他线程进入等待状态

Semaphore提供的方法

  • Semaphore(int permits) 创建具有给定的许可数和非公平的公平设置的Semaphore

  • Semaphore(int permits, boolean fair) 创建具有给定的许可数和给定的公平设置的Semaphore,true即为公平锁

  • void acquireUninterruptibly() 从此信号量中获取许可,不可中断

  • int availablePermits() 返回此信号量中当前可用的许可数

  • int drainPermits() 获取并返回立即可用的所有许可

  • protected Collection<Thread> getQueuedThreads() 返回一个 collection,包含可能等待获取的线程

  • int getQueueLength() 返回正在等待获取的线程的估计数目

  • boolean hasQueuedThreads() 查询是否有线程正在等待获取

  • boolean isFair() 如果此信号量的公平设置为 true,则返回 true

  • boolean tryAcquire() 仅在调用时此信号量存在一个可用许可,才从信号量获取许可

  • boolean tryAcquire(long timeout, TimeUnit unit) 如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可

内部原理分析

类图

AQS是基础组件,只负责核心并发操作,如加入或维护同步队列,控制同步状态,等,
而具体的加锁和解锁操作交由子类完成,
因此子类Semaphore共享锁的获取与释放需要自己实现,
这两个方法分别是获取锁的tryAcquireShared(int arg)方法和释放锁的tryReleaseShared(int arg)方法,这点从Semaphore的内部结构完全可以看出来

Semaphore的内部类公平锁(FairSync)和非公平锁(NoFairSync)各自实现不同的获取锁方法即tryAcquireShared(int arg),
毕竟公平锁和非公平锁的获取稍后不同,
而释放锁tryReleaseShared(int arg)的操作交由Sync实现,因为释放操作都是相同的,因此放在父类Sync中实现当然是最好的

源码分析

默认非公平锁

初始化信号量的时候 传入的 permits 参数 最终会赋值到aqs的state变量
并对state进行cas操作调用Semaphore的acquire()方法后,
执行过程是这样的,
当一个线程请求到来时,如果state值代表的许可数足够使用,
那么请求线程将会获得同步状态即对共享资源的访问权,并更新state的值(一般是对state值减1),
但如果state值代表的许可数已为0,则请求线程将无法获取同步状态,
线程将被加入到同步队列并阻塞,
直到其他线程释放同步状态(一般是对state值加1)才可能获取对共享资源的访问权

先获取state的值,并执行减法操作,得到remaining值,
如果remaining大于等于0,那么线程获取同步状态成功,可访问共享资源,并更新state的值,
如果remaining小于0,那么线程获取同步状态失败,将被加入同步队列(通过doAcquireSharedInterruptibly(arg))采用无锁(CAS)并发的操作保证对state值修改的安全

1、在方法中,由于当前线程没有获取同步状态,因此创建一个共享模式(Node.SHARED)的结点并通过addWaiter(Node.SHARED)加入同步队列,2、加入完成后,当前线程进入自旋状态,首先判断前驱结点是否为head,a、如果是,那么尝试获取同步状态并返回r值,如果r大于0,则说明获取同步状态成功,将当前线程设置为head并传播,传播指的是,同步状态剩余的许可数值不为0,通知后续结点继续获取同步状态,到此方法将会return结束,获取到同步状态的线程将会执行原定的任务。b、如果前驱结点不为head或前驱结点为head并尝试获取同步状态失败,那么调用shouldParkAfterFailedAcquire(p, node)方法判断前驱结点的waitStatus值是否为SIGNAL并调整同步队列中的node结点状态,如果返回true,那么执行parkAndCheckInterrupt()方法,将当前线程挂起并返回是否中断线程的flag


在AQS中存在一个变量state,当我们创建Semaphore对象传入许可数值时,
最终会赋值给state,state的数值代表同一个时刻可同时操作共享数据的线程数量,
每当一个线程请求(如调用Semaphored的acquire()方法)获取同步状态成功,
state的值将会减少1,直到state为0时,表示已没有可用的许可数,
也就是对共享数据进行操作的线程数已达到最大值,其他后来线程将被阻塞,
此时AQS内部会将线程封装成共享模式的Node结点,加入同步队列中等待并开启自旋操作。
只有当持有对共享数据访问权限的线程执行完成任务并释放同步状态后,
同步队列中的对于的结点线程才有可能获取同步状态并被唤醒执行同步操作,注
意在同步队列中获取到同步状态的结点将被设置成head并清空相关线程数据(毕竟线程已在执行也就没有必要保存信息了),
AQS通过这种方式便实现共享锁

本文使用 mdnice 排版

Semaphore 原理简介和使用相关推荐

  1. javascript原理_JavaScript程序包管理器工作原理简介

    javascript原理 by Shubheksha 通过Shubheksha JavaScript程序包管理器工作原理简介 (An introduction to how JavaScript pa ...

  2. Nginx 反向代理工作原理简介与配置详解

    Nginx 反向代理工作原理简介与配置详解 测试环境 CentOS 6.8-x86_64 nginx-1.10.0 下载地址:http://nginx.org/en/download.html 安装 ...

  3. DeepLearning tutorial(1)Softmax回归原理简介+代码详解

    FROM: http://blog.csdn.net/u012162613/article/details/43157801 DeepLearning tutorial(1)Softmax回归原理简介 ...

  4. DeepLearning tutorial(3)MLP多层感知机原理简介+代码详解

    FROM:http://blog.csdn.net/u012162613/article/details/43221829 @author:wepon @blog:http://blog.csdn.n ...

  5. DeepLearning tutorial(4)CNN卷积神经网络原理简介+代码详解

    FROM: http://blog.csdn.net/u012162613/article/details/43225445 DeepLearning tutorial(4)CNN卷积神经网络原理简介 ...

  6. 【Android 异步操作】Handler ( 主线程中的 Handler 与 Looper | Handler 原理简介 )

    文章目录 一.主线程中的 Handler 与 Looper 二.Handler 原理简介 一.主线程中的 Handler 与 Looper Android 系统中 , 点击图标启动一个应用进程 , 就 ...

  7. 量子计算机编程原理简介 和 机器学习

    量子计算机编程原理简介 和 机器学习 本文翻译自D-Wave公司网站 www.dwavesys.com/en/dev-tutorial-intro.html D-wave公司在2007年就声称实现了1 ...

  8. DL之CNN:卷积神经网络算法简介之原理简介——CNN网络的3D可视化(LeNet-5为例可视化)

    DL之CNN:卷积神经网络算法简介之原理简介--CNN网络的3D可视化(LeNet-5为例可视化) CNN网络的3D可视化 3D可视化地址:http://scs.ryerson.ca/~aharley ...

  9. DL之CNN:卷积神经网络算法简介之原理简介(步幅/填充/特征图)、七大层级结构(动态图详解卷积/池化+方块法理解卷积运算)、CNN各层作用及其可视化等之详细攻略

    DL之CNN:卷积神经网络算法简介之原理简介(步幅/填充/特征图).七大层级结构(动态图详解卷积/池化+方块法理解卷积运算).CNN各层作用及其可视化等之详细攻略 目录 CNN 的层级结构及相关概念 ...

最新文章

  1. linux 判断网线是否插入
  2. 消费者最关心的就是你的用户体验,以及保证产品品质,保证价格和服务
  3. 表格布局(TableLayout)及重要属性
  4. Android-Animations的使用大全之二:Frame Animation和其他
  5. angular5使用httpclient时解决跨域问题
  6. 干货 | 高效阅读英文文献你必须知道的技巧
  7. 【android自定义控件】button样式自定义二
  8. Fragstats官方入门教程4 移动窗口分析
  9. 中班机器人歌曲_幼儿园机器人教案音乐
  10. 联想计算机电源风扇怎样清理,风扇除尘功能说明:联想电源管理V1.0、V7.0、V8.0及早期机型除尘说明...
  11. 光纤的用途及主要种类
  12. DongDong认亲戚 来源:牛客网
  13. 计算机网络应用层题库
  14. 用Python做单变量数据集的异常点分析
  15. 在Geany里配置python3的方法!!!含window10下载Geany过程
  16. 中国知网html如何复制,中国知网如何快速导出参考文献的格式? 来看看吧
  17. 微信小程序开发工具安装破解
  18. 3A和ISP算法概念梳理
  19. Umeng—新浪登录问题
  20. 用python写一个ip查询工具库

热门文章

  1. listdir在python3_Python3 os.listdir() 方法
  2. python找不到自带的argparse_python argparse用法总结
  3. python收取wss数据_大宗商品现货数据不好拿?商品季节性难跟踪?Python爬虫一键解决没烦恼...
  4. Spring Cloud云服务架构 - HongHu云架构代码结构分析
  5. 【Hadoop】HIVE 数据表 使用
  6. SICP:Building Abstractions with Data
  7. docker高级应用之智能添加与修改防火墙规则
  8. 大话项目管理工具之Confluence篇
  9. MICROSOFT REPORT VIEWER 2012之无法加载相关的dll
  10. 自回归模型/向量自回归模型