用信号量锁定:一个例子

并发是带来有趣挑战的一个方面。 如果处理不当,会导致种族状况,这会使人们感到困惑,因为这些问题有时会突然出现,并且有时会完美无缺地发挥作用。

当处理访问公共资源的并发线程时,Java语言提供了许多处理竞争条件的方法。 一些包括;

  1. 使用volatile关键字
  2. 使用java.util.concurrent和 java.util.concurrent.atomic中可用的类
  3. 同步块
  4. 使用信号量

当然,可能还有很多我可能不知道的事情。 今天,我想向大家展示的例子是使用
信号量 。 它是从JDK 1.5引入的,使开发人员能够无缝获取和释放锁。 我还将显示的示例是一个假设的场景,该场景仅用于描述使用信号量可以实现的效果,因此请不要看代码的固有细节:)。

因此,在这种情况下,存在一个内存缓存中保存了类型为
'人'。 用户可以使用缓存插入和检索记录。 这里的问题是我们将使用信号量来控制对内存缓存的并发访问。 现在,我不想给您带来更多文本,让我们开始业务并显示一些代码;

import java.util.concurrent.Semaphore;/*** This class will allow thread to acquire and release locks as required* * @author dinuka.arseculeratne* */
public class PersonLock {/*** We do not want multiple lock objects lying around so we make ths class* singleton*/private PersonLock() {}/*** Bill Pugh's way of lazy initializing the singleton instance* * @author dinuka.arseculeratne* */private static class SingletonHolder {public static final PersonLock INSTANCE = new PersonLock();}/*** Use this method to get a reference to the singleton instance of* {@link PersonLock}* * @return the singleton instance*/public static PersonLock getInstance() {return SingletonHolder.INSTANCE;}/*** In this sample, we allow only one thread at at time to update the cache* in order to maintain consistency*/private Semaphore writeLock = new Semaphore(1);/*** We allow 10 concurrent threads to access the cache at any given time*/private Semaphore readLock = new Semaphore(10);public void getWriteLock() throws InterruptedException {writeLock.acquire();}public void releaseWriteLock() {writeLock.release();}public void getReadLock() throws InterruptedException {readLock.acquire();}public void releaseReadLock() {readLock.release();}
}

此类将处理获取和释放使我们的缓存线程安全所需的锁的过程。 我在这里使用了两个单独的锁进行读写。 其背后的原理是允许用户读取数据,尽管在读取时可能已过时。

请注意,我已经使用
这里的“十”表示十个线程可以同时获取锁并出于读取目的访问缓存。 接下来,您可以在写锁中看到,我已经使用了“ 一个” ,表示一次只有一个线程可以访问缓存以将项目放入缓存。 这对于保持缓存内的一致性很重要。 也就是说,我不希望有多个线程试图将项目插入到地图中,这将导致不可预测的行为(至少在某些情况下)。 使用信号量获取锁的方式主要有两种。

1. Acquisition() :是一个阻塞调用,它等待直到释放锁或线程被中断为止

2. tryAcquire() :是一个非阻塞调用,它将立即返回并返回true或false,表示是否已获得锁定。

在这里,我使用了阻塞获取调用,因为我希望线程等待直到锁可用。 当然,这取决于您的用例。 您还可以在tryAcquire()方法中定义超时期限,以使线程不会无限期地等待锁定。

接下来,下面的存储类显示了我如何使用锁类在缓存中插入和读取数据。

import java.util.HashMap;
import java.util.Map;/*** A mock storage to hold the person objects in a map* * @author dinuka.arseculeratne* */
public class PersonStorage {private Map<Integer, Person> personCache = new HashMap<Integer, Person>();private int counter = 0;/*** This class is made singleton and hence the constructor is made private*/private PersonStorage() {}/*** Bill Pugh's way of lazy initializing the singleton instance* * @author dinuka.arseculeratne* */private static final class SingletonHolder {public static final PersonStorage INSTANCE = new PersonStorage();}/*** Use this method to get a reference to the singleton instance of* {@link PersonStorage}* * @return the singleton instance*/public static PersonStorage getInstance(){return SingletonHolder.INSTANCE;}/*** Inserts the person into the map. Note that we use defensive copying so* that even if the client changes the object later on, those changes will* not be reflected in the object within the map* * @param person*            the instance of {@link Person} to be inserted* @return the key which signifies the location of the person object* @throws InterruptedException*/public int putPerson(Person person) throws InterruptedException {Person copyPerson = person.copyPerson();personCache.put(++counter, copyPerson);return counter;}/*** Here as well we use defensive copying so that the value of the object* reference within the map is not passed in to the calling party.* * @param id*            the id representing the location of the object within the map* @return the instance of the {@link Person} represented by the key passed*         in* @throws InterruptedException*/public Person retrievePerson(int id) throws InterruptedException {PersonLock.getInstance().getReadLock();if (!personCache.containsKey(id)) {throw new RuntimeException('Key is not found');}PersonLock.getInstance().releaseReadLock();return personCache.get(id).copyPerson();}}

显然,代码也可以在没有锁的情况下工作,但是问题是应用程序将不一致,并且每次运行都会提供不同的结果。 这不是您希望应用程序执行的操作,因此使用锁可以确保应用程序始终运行。

最后是一个小型测试类,以展示其工作方式; 并不是在这里我们在调用putPerson()方法之前获得了锁,并在finally块中释放了该锁,以保证释放该锁。

/*** A test class to demonstrate the locking at work* * @author dinuka.arseculeratne* */
public class TestLock {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {Person p1 = new Person(1L, 'Test1', 'XYZ');try {
PersonLock.getInstance().getWriteLock();
PersonStorage.getInstance().putPerson(p1);} catch (InterruptedException e) {// Exception handling need to be donee.printStackTrace();}finally{PersonLock.getInstance().releaseWriteLock();}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {Person p2 = new Person(2L, 'Test123', 'ABC');try {
PersonLock.getInstance().getWriteLock();PersonStorage.getInstance().putPerson(p2);} catch (InterruptedException e) {// Exception handling need to be done}finally{PersonLock.getInstance().releaseWriteLock();}}});t1.start();t2.start();System.out.println(PersonStorage.getInstance().retrievePerson(2));}
}

以上是我对使用Sempahores来确保代码线程安全的简短介绍的总结,对于任何想使用该代码的人来说,都可以从
在这里 。 尝试删除Storage类中的锁,并查看其在每次运行中的行为。 您将看到可能发生的比赛情况。

参考: 使用信号灯锁定:我们的JCG合作伙伴 Dinuka Arseculeratne 的示例,来自“ IT之旅”博客。


翻译自: https://www.javacodegeeks.com/2012/10/locking-with-semaphore-example.html

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

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

相关文章

navicat连接linux远程数据库,使用Navicat forMySql远程连接Linux 系统上的数据库

使用Navicat for MySql远程连接Linux 系统上的数据库解决mysql"Access denied for userrootIP地址"问题1.问题说明&#xff1a;在MYSQL 中&#xff0c;用远程软件登陆服务器&#xff0c;有时出现&#xff1a;Access denied for user rootlocalhost出现这种问题&#…

HTTPS 通俗简介

为什么需要HTTPS 9个问题搞懂 https 来源 HTTP是明文传输的&#xff0c;也就意味着&#xff0c;介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理 等。 举个最常见的例子&#xff0c;用户登陆。用户输入账号&#xff0c;密码&am…

CSS Modules入门教程

为什么引入CSS Modules 或者可以这么说&#xff0c;CSS Modules为我们解决了什么痛点。针对以往我写网页样式的经验&#xff0c;具体来说可以归纳为以下几点&#xff1a; 全局样式冲突 过程是这样的&#xff1a;你现在有两个模块&#xff0c;分别为A、B,你可能会单独针对这两…

单点登录(一):思考

单点登录&#xff08;后文简称&#xff1a;sso&#xff09;的定义是在多个应用系统中&#xff0c;用户只需要登录一次就可以访问所有相互信任的应用系统&#xff08;摘自百度百科&#xff09;。整个流程中涉及到的角色有&#xff1a;用户。应用服务器&#xff0c;即业务系统。单…

热电偶校验仪_热电偶校验方法_热电偶的使用方法及维修经验

一、遵照仪表接线图进行准确接线通电后&#xff0c;仪表先是显示仪表的热电偶分度号&#xff0c;接着显示仪表量程范围&#xff0c;再测仪表显示设定温度&#xff0c;数显仪表显示测量温度。若仪表数码管显示不是发热体的温度&#xff0c;而显示“OVER”、“0000”或“000”等状…

linux svn checkout密码,linux的svn之checkout命令

linux的checkout命令是linux的svn的常用命令之一。下面由秋天网 Qiutian.ZqNF.Com小编为大家搜集整理了linux的svn之checkout命令的相关知识&#xff0c;希望对大家有帮助!linux的svn之checkout命令常用检出命令&#xff1a;svn co http://路径(目录或文件的全路径) [本地目录…

Java 7:满足Fork / Join框架

JSR-166&#xff08;y&#xff09;是Java 7中包含的此新功能的正式名称。如果您发现名称中有一个“ y”&#xff0c;这是因为自Java 5起就添加了JSR-166&#xff08;并发实用程序&#xff09; &#xff0c;但它不会就此停止&#xff0c;因为已经有计划在JSR-166&#xff08;e&a…

css3总结之居中

居中在前端布局上很常见&#xff0c;也很常用&#xff0c;也是最基本的技巧。居中效果在方向控制上基本可以分解成水平居中&#xff0c;垂直居中和水平垂直居中。 针对调整的元素不同&#xff0c;具体的处理方式上有些差异。这里我们先不讲绝对定位下的居中&#xff0c;绝对定位…

PHP进程及进程间通信

一、引言 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。换句话说就是&#xff0c;在系统调度多个cpu的时候&#xff0c;一个程序的基本单元。进程对于大多数的语言都不是一个陌生的概念&#xff0c;作为"世界上最好的语言PHP"当然也例外。 二、环境…

福州java培训哪里好_南通java培训哪家好

渡课IT教育成立于2006年&#xff0c;14年来&#xff0c;我们累计输送学员达 6000 &#xff0c;其中南通地区输送50%&#xff0c;上海 40%&#xff0c;其他地区 10%&#xff0c;学员1年后的平均薪水达 9860 元&#xff1b;受到1000用人单位的赞誉与支持。Java开发的需求量在北上…

Linux 服务器注意事项

1.创建时 数据文件一定分盘挂载 2.LVM 虚拟磁盘卷是否创建 有争议&#xff1f;&#xff1f;&#xff1f;3.hosts 文件 最好添加本机映射 主机名 127.0.0.1 4.iptables 开启转载于:https://www.cnblogs.com/centos2017/p/7896681.html

linux 查看下挂磁盘,linux下磁盘挂载与查看

df查看系统分区和使用情况使用方法&#xff1a;df-h(自动按照大小做单位适应显示)df-i(查看iNode使用情况)free查看..LABELdefaults默认选项&#xff1a;rw (可读写)sudi (加此选项后则该分区可为文件加s权限&#xff1b;如不需要则写为nosuid)dev(可以解析该分区下的块…

研究僵局–第2部分

调查死锁时最重要的要求之一就是要研究死锁。 在我的上一个博客中&#xff0c;我编写了一个名为DeadlockDemo代码&#xff0c;该代码使用一堆线程在一系列银行帐户之间转移随机数&#xff0c;然后陷入僵局。 该博客运行该代码以演示获取线程转储的几种方法。 线程转储只是一个…

从0开始接触html--第一天学习内容总结

第一天 总结: h1-h6 p 段落 hr br有序 ol li 无序 ul li 定义列表 dl dt dd块级元素&#xff1a;独占一行&#xff0c;h1-h6 p hr div行内元素&#xff1a;共占一行, em和i strong和b u del和s span块级分区元素&#xff1a;div header nav article footer行内分区元素&#…

连锁便利店管理系统有什么用

连锁便利店管理系统对于连锁便利店的运营和管理非常有用。以下是一些常见的用途&#xff1a; 1. 库存管理&#xff1a;连锁便利店通常需要管理多个门店的库存&#xff0c;管理系统可以帮助实时掌握各个门店的库存情况&#xff0c;包括商品数量、进货记录、库存调拨等。这样可以…

经常使用meta标签属性

《meta》 1.Keywords (keyword)说明&#xff1a;告诉搜索引擎你网页的keyword是什么。 使用方法&#xff1a;<meta name"keywords" content"SEO优化,SEO优化教程,站点优化,搜索引擎优化教程"> 2. Description (网页描写叙述)说明&#xff1a;Descrip…

浏览器打印设置横向打印_爱普生打印机无线连接设置

1、首先&#xff0c;把epsonl385打印机插上电源通电&#xff0c;待自检完成后&#xff0c;便可以设置。如果用户家里的无线路由器带有WPS(Wi-Fi Protected Setup)或QSS(又称快速安全设置)功能&#xff0c;那就简单多了。2、通过WPS或QSS无线路由器按钮连接&#xff0c;给无线路…

linux python定时任务调度,Python下定时任务框架APScheduler的使用

1.APScheduler简介&#xff1a;APScheduler是Python的一个定时任务框架&#xff0c;可以很方便的满足用户定时执行或者周期执行任务的需求&#xff0c;它提供了基于日期date、固定时间间隔interval 、以及类似于Linux上的定时任务crontab类型的定时任务。并且该框架不仅可以添加…

图片和文件上传js剖析

/** * 商户资质信息模块js * * 涉及页面组件 { * 上传组件&#xff08;UploadFileComponent&#xff09; * } * * * 初始化工具&#xff08;init&#xff09; * * Author:Waver */var qualificationInfoModule (function() { // 上传文件类型 var UPLOAD_FILE_TYPE…

研究僵局–第1部分

我敢肯定我们都去过那里&#xff1a;太晚了&#xff0c;您饿了&#xff0c;服务器已挂起&#xff0c;或者应用程序正在以蜗牛的速度运行&#xff0c;并且有人喘着气想要您解决问题&#xff0c;然后再去解决。 您的应用程序意外挂起的可能原因之一是称为死锁的线程问题。 无需赘…