Java并发教程–信号量

这是我们将要进行的Java并发系列的第一部分。 具体来说,我们将深入探讨Java 1.5及更高版本中内置的并发工具。 我们假设您对同步和易失性关键字有基本的了解。

第一篇文章将介绍信号量-特别是对信号量进行计数 。 信号量是用于限制对资源访问的经常被误解和使用不足的工具。 对于其他控制对资源的访问的方式,它们将被忽略。 但是信号量为我们提供了一个超越常规同步和其他工具所能提供的工具集的工具集。

那么什么是信号量? 想到信号量的最简单方法是将其视为允许n个单位被获取并提供获取和释放机制的抽象。 它安全地允许我们确保在给定的时间只有n个进程可以访问特定资源

一切都很好,但是这将达到什么目的呢? 好吧,这是一个示例,将有助于解释其用法。 它使用位于1.5。中的java.util.concurrent包中精心设计的Semaphore类。

限制连接

也许我们有一个过程可以通过HTTP定期为我们下载资源。 我们不想向任何主机发送垃圾邮件,同时,我们想限制正在建立的连接数,因此我们不会耗尽允许的有限文件句柄或出站连接。 一种简单的方法是使用信号量:

public class ConnectionLimiter {private final Semaphore semaphore;private ConnectionLimiter(int maxConcurrentRequests) {semaphore = new Semaphore(maxConcurrentRequests);}public URLConnection acquire(URL url) throws InterruptedException,IOException {semaphore.acquire();return url.openConnection();}public void release(URLConnection conn) {try {/** ... clean up here*/} finally {semaphore.release();}}
}

对于资源有限的问题,这是一个很好的解决方案。 对acquire()的调用将阻塞,直到获得许可为止。 信号灯的优点在于,它隐藏了管理访问控制,计算许可数以及确保正确的线程安全性的所有复杂性。

危险性

与大多数锁定或同步方法一样,存在一些潜在问题。

要记住的第一件事是, 始终释放您获得的东西 。 这是通过使用try..finally构造完成的。

使用信号量时,还有其他不太明显的问题可能会降临您。 以下课程显示了死锁,只有您中最幸运的人才能避免。 您会注意到,获得两个信号量许可的两个线程的执行顺序相反。 (为简洁起见,try..finally最终被省去了)。

public static void main(String[] args) throws Exception {Semaphore s1 = new Semaphore(1);Semaphore s2 = new Semaphore(1);Thread t = new Thread(new DoubleResourceGrabber(s1, s2));// now reverse them ... here comes trouble!Thread t2 = new Thread(new DoubleResourceGrabber(s2, s1));t.start();t2.start();t.join();t2.join();System.out.println("We got lucky!");
}private static class DoubleResourceGrabber implements Runnable {private Semaphore first;private Semaphore second;public DoubleResourceGrabber(Semaphore s1, Semaphore s2) {first = s1;second = s2;}public void run() {try {Thread t = Thread.currentThread();first.acquire();System.out.println(t + " acquired " + first);Thread.sleep(200); // demonstrate deadlocksecond.acquire();System.out.println(t + " acquired " + second);second.release();System.out.println(t + " released " + second);first.release();System.out.println(t + " released " + first);} catch (InterruptedException ex) {ex.printStackTrace();}}
}

如果运行此程序,则很有可能会挂起一个进程。 锁排序的问题与Java中的常规互斥锁或同步一样,也适用于信号量。 在某些情况下,超时(请参阅本文后面的tryAcquire()注释)可用于防止死锁导致进程挂起,但是死锁通常是可以避免的逻辑错误的征兆。 如果您不熟悉死锁,建议您仔细阅读它们。 维基百科上有一篇关于死锁的文章,该文章同样适用于所有语言。

使用信号量(包括二进制信号量,即互斥体)时应注意的主要事项是:

  • 获取后不释放(丢失的释放调用或引发异常并且没有finally块)
  • 长时间保持信号量,导致线程饥饿
  • 死锁(如上所示)

有用的信号灯技巧

Java中Semaphores的一个有趣的特性是, 不必通过与Acquisition相同的线程来调用release 。 这意味着您可以具有一个线程限制器,该线程限制器可以通过调用acquire()来基于信号量池或创建线程。 然后,正在运行的线程可以在完成时释放其自己的信号灯许可。 这是Java中普通互斥锁所没有的有用属性。

另一个技巧是在运行时增加许可数量 。 与您可能会猜到的相反,信号量中的许可数量不是固定的,并且即使未进行相应的acquire()调用,对release()的调用也会始终增加许可的数量。 请注意,如果在没有进行acquire()的情况下错误地调用release() ,这也会导致错误。

最后,在Java的Semaphore中有一些有用的方法要熟悉。 方法AcquireInterruptible()将获取资源,如果资源被中断,则重新尝试。 这意味着没有对InterruptedException的外部处理。 tryAcquire()方法允许我们限制等待许可的时间-我们可以在没有许可的情况下立即返回,也可以等待指定的超时时间。 如果您以某种方式知道了无法轻松修复或跟踪的死锁,则可以通过使用带有适当超时的tryAcquire()来帮助防止锁定进程。

用途

计数信号量有哪些可能的用途? 请注意以下几点:

  • 限制对磁盘的并发访问(由于竞争磁盘搜寻,这可能会降低性能)
  • 线程创建限制
  • JDBC连接池/限制
  • 网络连接限制
  • 限制CPU或内存密集型任务

当然,信号量是访问控制和同步的一个很底层的构建块。 Java为我们提供了Java 1.5及更高版本中引入的大量并发机制和策略。 在接下来的文章中,我们将介绍一些更抽象的并发管理方法,包括执行器,BlockingQueues,Barriers,Future以及一些新的并发Collection类。

您发现信号量有什么用途? 通过发表评论让我们知道–我们喜欢语音软件。

参考: Java并发第1部分–来自我们的JCG合作伙伴的信号灯 ,在Carfey Software博客上 。

相关文章 :
  • Java并发教程–重入锁
  • Java并发教程–线程池
  • Java并发教程–可调用,将来
  • Java并发教程–阻塞队列
  • Java并发教程– CountDownLatch
  • Exchanger和无GC的Java
  • Java Fork / Join进行并行编程
  • Java最佳实践–队列之战和链接的ConcurrentHashMap
  • 如何在不到1ms的延迟内完成100K TPS
  • 使用迭代器时如何避免ConcurrentModificationException
  • 改善Java应用程序性能的快速技巧
相关片段:
  • 阻塞队列示例以执行命令
  • 限制URL连接的信号量示例
  • 执行命令的同步队列示例
  • 更一般的等待/通知机制的CountDownLatch示例

翻译自: https://www.javacodegeeks.com/2011/09/java-concurrency-tutorial-semaphores.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374187.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android surfaceview 大小_Android 使用Camera2 API采集视频数据

Android 视频数据采集系列的最后一篇出炉了,和前两篇文章想比,这篇文章从系统API层面进行一些探索,涉及到的细节更多。初次接触 Camera2 API 会觉得它的使用有些繁琐,涉及到的类有些多,不过就像第一次使用Activity, Fr…

java生成随机字符串

学习java comparable特性时候,定义如下Student类,需要需要随机添加学生姓名以及学号和成绩,这是java如何随机生成名字,根据我的查询,我找到目前java库支持两种方法。 1. org.apache.commons.lang3.RandomStringUtils类…

使用SharedPreferenes存取数据

//使用SharedPreference存储数据 public void on(View view){     //获取用户名和密码     String nameeditText1.getText().toString();     String numbereditText2.getText().toString();     //判断checkBox是否为勾选      CheckBox box(CheckBox…

使用Java VisualVM分析您的应用程序

当您需要发现应用程序的哪个部分消耗更多的CPU或内存时,必须使用探查器执行此操作。 默认情况下,Sun JDK中附带的一个探查器是Java VisualVM。 这个事件探查器非常简单易用,功能强大。 在这篇文章中,我们将看到如何安装它并使用它…

ArcSDE for SQL Server安装及在ArcMap中创建ArcSDE连接

ArcSDE for SQL Server安装及在ArcMap中创建ArcSDE连接 原文:ArcSDE for SQL Server安装及在ArcMap中创建ArcSDE连接安装ArcSDE for SQL Server,最后一步成功后的界面如下:在ArcMap中创建ArcSDE连接,截图如下:posted on 2016-08-0…

java反射main方法参数注意

public class ReflectMethodMain {public static void main(String[] args) throws Exception {Method methodMainTestArgument.class.getMethod("main", String[].class);/*jdk 1.4之前的版本不支持可变参数,对组类的参数会自动拆包然后用来匹配数据参数…

python调用c函数传字符串参数_Python使用ctypes模块调用DLL函数之传递数值、指针与字符串参数...

在Python语言中,可以使用ctypes模块调用其它如C语言编写的动态链接库DLL文件中的函数,在提高软件运行效率的同时,也可以充分利用目前市面上各种第三方的DLL库函数,以扩充Python软件的功能及应用领域,减少重复编写代码、…

沁恒CH554 KEIL环境搭建

首先下载WCHISPTool_Setup.exe http://www.wch.cn/products/CH554.html 123这三个可下载的都下吧,后面开发都要用的 安装好后运行,菜单栏上,功能->添加WCH MCU到KEIL器件库 这时候在KEIL安装目录里面的UV4文件夹下可以看到wch.cdb的文件…

【CV论文阅读】Rank Pooling for Action Recognition

这是期刊论文的版本,不是会议论文的版本。看了论文之后,只能说,太TM聪明了。膜拜~~ 视频的表示方法有很多,一般是把它看作帧的序列。论文提出一种新的方法去表示视频,用ranking function的参数编码视频的帧序列。它使用…

java不要在常量和变量中出现易混淆的字母

public class proposal {public static void main(String[] args) {long i1l; System.out.println("i的两倍是:"(ii));System.out.println("i的两倍是:"ii); //注意此处和上面的有很大的区别} }输出:211/** 注意:* …

VS2019 WPF制作OTA上位机(一)新建工程

首先创建新项目,文件 -> 新建 -> 项目 下拉菜单选择C#和Window,选择WPF应用程序,下一步 输入项目名,下一步 这里选择.NET 5.0,也可以选择其他的,个人习惯.NET,点击创建 这时候出现初始…

户籍恢复需要体检吗_脑梗死后脚麻能恢复吗?需要多久能恢复呢?

脑梗死之后脚部麻木,这个有一部分是能够恢复的,但是相对而言,恢复的时间比较长,在临床当中出现脚麻主要是因为梗死破坏了患者的感觉神经中枢从而造成。脚部感觉麻木,瘙痒或者是有蚂蚁在上面爬的感觉。而且有的更加严重…

Alpha版本测试报告

一、测试计划 Alpha版本即将发布,我们组织队员进行这一版本的测试。 测试主要针对两方面:浏览器兼容性和功能完善性。 测试分兼容性测试与功能完善性两部分,兼容性测试分Windows操作系统、Linux系操作系统、Mac OS X操作系统以及手机端Androi…

在J2SE应用程序中模拟CDI的会话和请求范围

我们目前正在考虑将Naked Objects框架重构为使用JSR-330(依赖注入)和面向EE的老大哥JSR-299(CDI)。 使用香草JSR-330是不费吹灰之力的,但是我们想利用JSR-299中的一些不错的功能(例如事件和装饰器&#xff…

VS2019 WPF制作OTA上位机(二)获取bin文件路径

OTA升级是通过无线通信远程把bin文件内容传输到单片机,完成升级。 因此上位机需要获取bin文件的路径,读取bin文件内容,将内容分割依次发送(因为单片机的接收缓存不会开得和bin文件一样大(十几K甚至几十K)&a…

java 线程“生产/消费”模型1

/*资源类*/ public class ShareValue {private int total;public ShareValue(int total){this.totaltotal;}//生产void putValue(int value){totalvalue;}//消费资源int getValue(int value){if(total-value>0){total-value;}else{valuetotal;total0;System.out.println(&qu…

PHP - 代码分离

总代码&#xff1a; <?php/** Version&#xff1a;1.0* CreateTime&#xff1a;2015年11月11日* Author&#xff1a;HF_Ultrastrong*///引入公共文件,在公共文件中创建&#xff0c;相对于项目的绝对路径require dirname(__FILE__)./includes/common.inc.php; ?&…

原生js封装table表格操作,获取任意行列td,任意单行单列方法

V1.001更新增加findTable-min.js 本次更新&#xff0c;优化了代码性能方面&#xff0c;增加了部分新功能&#xff0c;可以获取多个table表格批量操作。 考虑到本人后面的项目中可能涉及到大量的表格操作&#xff0c;提前先封了 一个简单的操作方法&#xff0c;日后再加完善&…

Spring陷阱:事务测试被认为是有害的

Spring杀手级功能之一是容器内集成测试 。 尽管EJB多年来一直缺乏此功能&#xff08;Java EE 6终于解决了这个问题&#xff0c;但是我还没测试过&#xff09;&#xff0c;但是Spring从一开始就允许您从Web层开始&#xff0c;通过所有服务来测试整个堆栈。到数据库的方式。 数据…

python xlwt写入已有表_Python中,添加写入数据到已经存在的Excel文件

1.安装xlrd、xlwt、xlutilshttps://pypi.org/project/xlutils/pip安装&#xff1a;cmd下输入&#xff1a;pip install xlrd #读取exclepip install xlwt #写入exclepip install xlutils #操作 Excel 文件的实用工具&#xff0c;如复制、分割、筛选等2.代码主要部分实现import x…