Java多线程并发之读写锁
本文主要内容:读写锁的理论;通过生活中例子来理解读写锁;读写锁的代码演示;读写锁总结。通过理论(总结)-例子-代码-然后再次总结,这四个步骤来让大家对读写锁的深刻理解。
本篇是《凯哥(凯哥Java:kagejava)并发编程学习》系列之《Lock系列》教程的第七篇:《Java并发包下锁学习第七篇:读写锁》。
一:读写锁的理论
什么是读写锁?
多个线程同时读一个资源类是没有任何问题的,所以为了满足在并发的情况下,读取共享资源应该是可以同时进行的;但是,如果一个线程想要去写共享资源,就不应该再有其他线程可以对该共享资源进行读或者是写操作了。
即读写锁在同一时刻可以允许多个多线程访问,但是在写线程访问的时候,所有的读线程和其他写线程都会被阻塞。读写锁实际维护了一对锁,一个读锁,一个写锁,通过分离读锁和写锁,使得其并发性比独占式锁(排他锁)有了很大的提升。
为什么需要读写锁?
通过前面文章的学习,我们知道了ReentrantLock(下文简称:RLock)对象了。Rlock比起synchronized(下文简称Sync)来说有三个优点:RLock可以被中断;RLock可以有公平锁;RLock可以绑定多个条件。那么既然RLock比Sync有这么多优点,为什么还需要读写锁呢?
那是因为RLock是独占式(排他) 锁,即当线程1获取到资源的时候,其他线程不能再来操作共享资源了。就算是RLock的操作是读取的时候,其他线程也不能读取共享资源的操作。这在现实生活中是不符合逻辑的(在下文神话中读写锁的例子中我们就能体会到为什么不符合逻辑的),而且性能也比较慢。所以就有了读写锁的出现。
二:读写锁的理解
生活中读写锁的例子
例子一:我们大家去火车站乘车的时候,有个大大的公示屏幕,会告诉大家当前车次是否晚点。显示屏是给给所有乘客看的,如果火车晚点,对应车次后面就会被修改成晚点大约xxx分钟。这个修改的动作只能是火车站内部人员来操作的,我们乘客是不能操作的。这个过程,站在并发角度来分析的的话:电子屏幕是共享数据;千千万万的乘客是不同的线程;火车站内部工作人员也是不同的线程;乘客是读资源的线程,当一个线程来读取的时候,其他线程也可以读取操作的;火车站内部工作人员修改火车信息的时候,同时只能有一个工作人员来修改,不能两个都来修改。如果两个都来修改的话,上一秒显示晚点1min,下一秒显示正常。这个是不行的,乘客有可能会错过乘车的。所以修改的时候同时只能由一个工作人员来修改。
例子二:我们在玩王者荣耀的时候,有时候会遇到停服更新的。在不更新前,所有玩家都可以玩,当停服更新的时候,所有玩家就不能玩了。这个操作在并发角度来说:千千万万的玩家是读共享资源的;游戏维护者是写操作的。当停服更新的时候,读操作就被阻塞了,只能等写操作,也就是更新完成后,才可以接着玩。
通过上面两个例子我们可以分析到读写锁的三个参与者:共享资源;读对象;写对象。而且读和写一般是分离的。
三:读写锁的代码演示
我们就用火车站进站案例来模拟:
未使用锁的时候
先来看看屏幕对象:
再来看看多个工作人员更新操作及多个乘客获取操作:
查看运行结果:
从运行结果中,我们可以发现当工号未13的还没有更新完车次信息的时候,工号12和14的员工也来更新了。这种操作是不允许的。因为写操作要原子性,要独占。当工作人员甲在修改的时候车次信息的时候,其他工作人员不能同时修改同一个车次信息了。而且从乘客获取车次信息的数据来看,获取到的只是工号是13的。这个时候获取到的数据不一定是正确的了。所以,不使用锁是不行的。
使用排他锁
如果使用独占式做的话,我们查看运行结果:
从运行结果来看,再读取的时候,需要一个一个读取的。当16号乘客查看的时候,17号乘客是不能查看的。这个是不符合实际业务逻辑的。所以,独占式(排他锁)RLock在这里不适合。我们再来看看读写锁:
使用读写锁
先来看看使用读写锁的屏幕对象
再来看看运行结果:
从运行结果中,我们可以看到,工作人员是一个一个的操作完成的。当14号操作完成之后,13号和12号才可以操作的。这个符号我们正常的业务。乘客读取的时候,读取到的都是最后一次更新,这个也符合我们的业务。所以,通过读写锁来操作车站屏幕是可以的。
四:读写锁总结
4.1:wrLock类对象
同样包含了公平锁和非公平锁。
其中ReadLock是读锁对象;WriteLock是写锁对象。
4.2:使用语法
读操作使用ReadLock
编辑
写操作的时候,使用WriteLock对象:
4.3:总结
读写锁(ReentrantReadWriteLock),凯哥就简写rwLock。也可以实现公平和非公平的。其内部维护了一对锁:一个读锁(ReadLock对象),一个写锁(writeLock对象),通过读写分离的方式来提高并发性能。读写锁也叫共享锁。其共享是在读数据的时候,可以让多个线程同时进行读操作的。在写的时候具有排他性,其他读或者写操作都要被阻塞。
一般情况下,读写锁的性能都会比排他锁性能好,那是因为,大多数场景读操作多于写操作的。在读多与写的场景下,读写锁能够提供比排他锁更好的并性能和吞吐量。
欢迎来聊~
相关推荐
【火车票售票系统】是一个基于Java技术开发的前端应用程序,主要目标是实现对火车票的购买、查询、退票等操作。在这个系统中,前端部分使用Java语言进行编写,这表明开发者可能使用了Java Swing或JavaFX这样的GUI库...
【标题】"火车票管理系统(java 数据库)"是一个基于Java技术和数据库技术开发的系统,主要用于实现对火车站票务的管理。这个系统可能包含了售票、查询、退票等多种功能,旨在提高铁路票务工作的效率和准确性。 ...
【Java火车站售票系统】是一个基于Java编程语言实现的简单售票应用程序,主要面向初学者,旨在帮助他们理解基础的系统开发和编程概念。这个系统模仿了实际火车站售票过程中的部分功能,提供了一个直观的学习平台。 ...
【Java火车车次查询系统】是一个基于Java编程语言和数据库技术开发的课程设计项目,旨在帮助用户查询火车车次信息。这个系统包含了完整的源代码,为学习者提供了深入理解Java编程、数据库操作以及用户界面设计的实践...
【Java购票系统(火车站)】是一个综合性的软件项目,它主要使用Java编程语言来实现,旨在为用户提供在线火车票购买的服务。系统包含了多种关键功能,是学习和实践Java Web开发的优秀实例。在这个系统中,用户可以...
总的来说,这个“火车站订票系统”是JAVA编程实践的典范,它涵盖了JAVA语言的诸多核心概念和技术,包括面向对象设计、异常处理、集合框架、多线程以及网络编程等。对于学习JAVA的人来说,通过分析和理解这个系统,...
火车站售票管理系统是一个基于JavaSE(Java Standard Edition)开发的应用程序,主要用于模拟并处理火车站的售票业务。这个系统可能包含了购票、退票、查询余票、显示车次信息等多种功能,适用于学习Java编程的学生...
【JAVA火车售票系统】是一个基于Java编程语言开发的软件应用,主要用于模拟并实现现实生活中火车票的销售与管理功能。这个系统旨在为用户提供一个高效、便捷的售票平台,同时简化后台管理工作,使得管理员能够轻松地...
例如,如果用户输入北京作为始发站,上海作为终点站,系统将展示所有从北京出发到达上海的列车班次。 ##### 2. 反向站站查询模块 此模块为用户提供了一个便捷的方式来进行反向查询。用户只需要输入始发站和终点站,...
【火车站销售系统】是一个针对初学者设计的简单项目程序,主要目标是模拟火车站售票过程,帮助学生理解基础的软件开发流程和技术。这个项目对于想要学习编程、了解软件工程的初级开发者来说,是一个很好的实践平台。...
总结来说,这个Java实现的火车站售票系统模拟项目涉及了Java多线程编程、并发控制、线程通信、网络编程、设计模式以及数据结构等多个核心知识点,对于理解和实践Java在实际问题中的应用具有很高的价值。通过这样的...
【Java JDBC火车购票系统】是基于Java编程语言,利用Java Database Connectivity(JDBC)技术与MySQL数据库构建的一个实际应用项目。这个系统旨在模拟真实的火车票预订流程,为用户提供查询车次、预订、支付以及退票...
【Java+MySQL火车站售票系统】是一个基础的票务管理系统,主要使用Java编程语言进行前端和后端的开发,并结合MySQL数据库来存储和管理售票数据。这个系统可能适用于学习和初级阶段的项目实践,特别是对于那些正在...
Java火车售票系统是一个基于Java编程语言开发的应用程序,主要用于模拟实际生活中火车票的购买、查询、退票等操作。这个项目对于Java初学者或者想要深入理解面向对象编程、多线程、网络通信以及数据库交互的开发者来...
【Java模拟火车站售票系统源代码】是一个典型的计算机编程实践项目,它主要展示了如何利用Java语言构建一个简单的售票系统。在该系统中,开发者通常会设计并实现一系列类和方法,以便模拟真实的购票流程,包括查询...
【标题】"2014火车票抢票源码java" 涉及的主要知识点是基于Java编程语言的网络爬虫技术以及Web自动化处理,主要应用于抢购火车票的场景。2014年,由于互联网购票系统的普及,开发者利用编程技术编写抢票软件成为一种...
最全的全国火车站数据
《火车站售票系统(1)》 火车站售票系统是公共交通领域中的关键组成部分,它涉及到旅客购票、退票、改签等一系列业务流程,对于提高火车站运营效率和服务质量有着至关重要的作用。本系统的设计与实现旨在优化这一...
4. 存储和加载数据:程序可能还包括读写数据的功能,如从文件中加载车次信息,或者保存用户的购票记录。这可能涉及到Java的文件I/O操作,如FileInputStream和FileOutputStream。 5. 异常处理:为了确保程序的健壮性...