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

当处理访问公共资源的并发线程时,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

用信号量锁定:一个例子相关推荐

  1. [asp.net core]SignalR一个例子

    摘要 在一个后台管理的页面想实时监控一些操作的数据,想到用signalR. 一个例子 asp.net core+signalR 使用Nuget安装包:Microsoft.AspNetCore.Sign ...

  2. R语言使用lm构建线性回归模型、并将目标变量对数化(log10)实战:可视化模型预测输出与实际值对比图、可视化模型的残差、模型预测中系统误差的一个例子 、自定义函数计算R方指标和均方根误差RMSE

    R语言使用lm构建线性回归模型.并将目标变量对数化(log10)实战:可视化模型预测输出与实际值对比图.可视化模型的残差.模型预测中系统误差的一个例子 .自定义函数计算R方指标和均方根误差RMSE 目 ...

  3. python中self_一个例子带你入门Python装饰器

    ============ 欢迎关注我的公众号:早起python ============ 前言 在还未正式发布的python3.9中,有一个新功能值得关注,那就是任意表达式可以作为装饰器,如果你还不知 ...

  4. ftp服务器文件备份,数据备份是十分重要的,下面是通过ftp将本机数据备份到远程服务器的一个例子...

    数据备份是十分重要的,下面是通过ftp将本机数据备份到远程服务器的一个例子 以备份oracle数据为例 本机IP:192.168.0.1 远程IP:192.168.0.111 备份脚本 ora_bak ...

  5. Bootice1.34版本把grub4dos0.46a写入硬盘MBR失败一个例子

    Bootice1.34版本把grub4dos0.46a写入硬盘MBR失败一个例子         一个同事的台式机,BIOS启动,500GB硬盘,分了四个MBR分区,C盘是激活的主分区,第二个分区50 ...

  6. 用一个例子告诉你gdb调试工具如何使用

                                        用GDB调试程序 GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式 ...

  7. C++中const——由一个例子想到的

    前天同学实现了<C++ Primer>中关于虚函数的一个例子,拿过来问我,代码如下: #include<iostream> #include<string> usi ...

  8. UA PHYS515A 电磁理论II 静电学问题的一个例子

    UA PHYS515A 电磁理论II 静电学问题的一个例子 例 假设有一个中空球形导体,中空部分也是一个球形,半径为aaa,球心与导体相同,导体半径为bbb:球心处有一个+q+q+q的点电荷,距离圆心 ...

  9. UA MATH566 一个例子:什么是隐状态

    UA MATH566 一个例子:什么是隐状态 对试验结果的分析 对隐状态的分析 假设一个包里有三个色子,分别是色子A.色子B和色子C,每个色子的六个面上都标有1-4中的某个数字,其中色子A有两面标1. ...

  10. UA MATH566 统计理论7 还有一个例子:推导卡方检验

    UA MATH566 统计理论7 还有一个例子:推导卡方检验 均值已知 均值未知 前面的文章中我们已经推导了Z检验和T检验,Z检验是方差已知时比较单个或两个正态总体均值的方法:T检验是方差未知时比较单 ...

最新文章

  1. 将jsp页面转化为图片或pdf(一)(qq:2798641729)
  2. nginx php 配置 windows_Windows下配置Nginx使之支持PHP
  3. Centos 6.5下的OPENJDK卸载和SUN的JDK安装、环境变量配置
  4. iOS: How To Make AutoLayout Work On A ScrollView
  5. java etcd api_在java中如何使用etcd的v2 和v3 api获取配置,并且对配置的变化进行监控和监听...
  6. php 明天凌晨,用php判断时间戳来输出刚刚,分钟前,小时前昨天和时间
  7. MyBatis 延迟加载的三种加载方式深入,你get了吗?
  8. Python项目导出依赖包requirements.txt
  9. kiss原则包括什么_KISS原则
  10. kk每日一句:第一句
  11. java 替换 ppt内容_Java 替换PPT文档中的文本和图片
  12. 技术VC=技术+VC?技术VC公司如何生存?
  13. MYSQL-计算两个时间的时间差和工作日差
  14. 深入了解戴维斯双击和戴维斯双杀
  15. 目标检测算法之评价标准AP,mAP
  16. JAVA 2乘以8 方法_Java中用最有效率的方法算出2乘以8
  17. 无组件架构:你不需要知道的“新一代”前端架构模式
  18. python打开qq并登录_Python脚本简单实现打开默认浏览器登录人人和打开QQ的方法...
  19. Django 字段加密存储并支持检索
  20. Outlook里面插入图片不是附件的形式

热门文章

  1. skimage直方图如何保存_LightGBM的参数详解以及如何调优
  2. camel apache_Apache Camel 3只有2个月的路程
  3. 如何做到服务器虚拟化_尽可能地做到无服务器,但不止于此
  4. 接口方法javadoc注释_继承Javadoc方法注释
  5. jdk170不支持注释_JDK 9 @不建议使用的注释增强功能
  6. java键盘事件键值表_Java的20年:重大事件的时间表
  7. flyway数据迁移_使用Flyway在Java EE中进行数据库迁移
  8. Spring @RequestParam批注
  9. junit 运行_运行,JUnit! 跑!!!
  10. gradle文件不识别_识别Gradle约定