java 读写锁详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt124
在java多线程中,为了提高效率有些共享资源允许同时进行多个读的操作,但只允许一个写的操作,比如一个文件,只要其内容不变可以让多个线程同时读,不必做排他的锁定,排他的锁定只有在写的时候需要,以保证别的线程不会看到数据不完整的文件。
下面是个关于多线程读写锁的例子,我稍微做了下修改,蛮容易理解的,来至于http://www.highya.com/redirect.php?fid=113&tid=7180&goto=nextoldset。
这里模拟了这样一个场景: 在ReadWriteLockOperator对象里设置一个共享资源 shareResources 。
有3个读者(A, B, C)一直连续的从 shareResources 获取信息, 然后输出到控制台 ;有一个作者每隔60秒往shareResources 加入信息, 加信息的过程相对耗时, 在这段时间, 任何读者都不能访问 shareResources。
写了4个类来验证这种情况,只在windows下做了测试。
ReadTask.java 读任务
WriteTask.java 写任务
ReadWriteLockLogic.java 读写操作的逻辑
ReadWriteLockTest.java 带有main方法的测试类
---------------------------------------混哥线-----------------------------------------------
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class ReadTask extends Thread { //logic bean private ReadWriteLockLogic readWriteLockOperator; //读者 private String reader; public ReadTask(ReadWriteLockLogic readWriteLockOperator, String reader) { this.readWriteLockOperator = readWriteLockOperator; this.reader = reader; } private ReadTask(){} // 执行任务 public void run() { if(this.readWriteLockOperator != null){ try { while(!isInterrupted()){ Thread.sleep(200); System.out.println(reader + " read:" + Thread.currentThread().toString() + " : " + this.readWriteLockOperator.read()); } } catch (Exception e) { // TODO: handle exception } } }} |
-------------------------------------------------------------------------------------
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class WriteTask extends Thread{ //logic bean private ReadWriteLockLogic readWriteLockOperator; //作者 private String writer; public WriteTask(ReadWriteLockLogic readWriteLockOperator, String writer) { this.readWriteLockOperator = readWriteLockOperator; this.writer = writer; } private WriteTask(){} // 一个很耗时的写任务 public void run() { try { while(!isInterrupted()){ Thread.sleep(100); this.readWriteLockOperator.write(this.writer, "hehehhe"); } } catch (Exception e) { // TODO: handle exception } }} |
----------------------------------------------------------------------------------
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
import java.util.ArrayList;import java.util.List;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;//读写操作的逻辑public class ReadWriteLockLogic { // 初始化一个 ReadWriteLock private ReadWriteLock lock = new ReentrantReadWriteLock(); //共享资源 private List<String> shareResources = new ArrayList<String>(0); //读 public String read() { // 得到 readLock 并锁定 Lock readLock = lock.readLock(); readLock.lock(); try { // 读相对省时,做空循环 大约0.5second for(int i=0 ;i<2500000; i++){ System.out.print(""); } // 做读的工作 StringBuffer buffer = new StringBuffer(); for (String shareResource : shareResources) { buffer.append(shareResource); buffer.append("\t"); } return buffer.toString(); } finally { readLock.unlock();//一定要保证锁的释放 } } //写 public void write(String writer, String content) { // 得到 writeLock 并锁定 Lock writeLock = lock.writeLock(); writeLock.lock(); try { System.out.println(writer + " write ===" + Thread.currentThread().toString()); // 写比较费时,所以做空循环 大约13second for(int i=0 ;i<10000000; i++){ System.out.print(""); System.out.print(""); } // 做写的工作 int count = shareResources.size(); for (int i=count; i < count + 1; i++) { shareResources.add(content + "_" + i); } } finally { writeLock.unlock();//一定要保证锁的释放 } }} |
------------------------------------------------------------------------------------
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class ReadWriteLockTest { public static void main(String[] args) throws InterruptedException, ExecutionException { //1 创建一个具有排程功能的线程池 ScheduledExecutorService service = Executors.newScheduledThreadPool(5); //2 读写锁的logic bean ReadWriteLockLogic lockOperator = new ReadWriteLockLogic(); //3 生成一个可执行任务(该任务执行完毕可以返回结果 或者 抛出异常;而Runnable接口的run方法则不行) Runnable writeTask1 = new WriteTask(lockOperator, "作者A"); //4 延时0秒后每2秒重复执行writeTask1; service.scheduleAtFixedRate(writeTask1, 0, 60, TimeUnit.SECONDS); //5 创建3个读任务 Runnable readTask1 = new WriteTask(lockOperator, "作者B"); Runnable readTask2 = new ReadTask(lockOperator, "读者B"); Runnable readTask3 = new ReadTask(lockOperator, "读者C"); //6 延时0秒后每秒执行一次task1; service.scheduleAtFixedRate(readTask1, 1, 1, TimeUnit.SECONDS); service.scheduleAtFixedRate(readTask2, 2, 1, TimeUnit.SECONDS); service.scheduleAtFixedRate(readTask3, 3, 1, TimeUnit.SECONDS); }} |
----------------------------------------------------------------------------------------
作者A write ===Thread[pool-1-thread-1,5,main]
作者B write ===Thread[pool-1-thread-4,5,main]
读者C read:Thread[pool-1-thread-3,5,main] : hehehhe_0 hehehhe_1
读者B read:Thread[pool-1-thread-2,5,main] : hehehhe_0 hehehhe_1
作者A write ===Thread[pool-1-thread-1,5,main]
................
通过观察控制台,可以看到作者a出现后,大约5秒作者b才会出现,而又过了5秒后,读者c和读者b同时会出现,接着5秒后,作者a又出现了。这说明了,读锁之间没有排斥,可以多线程持有并且排斥WriteLock的持有线程。而WriteLock是全部排斥的,是独占的,比较独!
下面是附赠的读写锁的小知识,来至http://www.txdnet.cn/essay/view.jsp?tid=1288670091703&cid=2
(a).重入方面其内部的WriteLock可以获取ReadLock,但是反过来ReadLock想要获得WriteLock则永远都不要想.
(b).WriteLock可以降级为ReadLock,顺序是:先获得WriteLock再获得ReadLock,然后释放WriteLock,这时候线程将保持Readlock的持有.反过来ReadLock想要升级为WriteLock则不可能,为什么?参看(a),呵呵.
(c).ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥.这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量.
(d).不管是ReadLock还是WriteLock都支持Interrupt,语义与ReentrantLock一致.
(e).WriteLock支持Condition并且与ReentrantLock语义一致,而ReadLock则不能使用Condition,否则抛出UnsupportedOperationException异常.
java 读写锁详解的更多相关文章
- ReentrantReadWriteLock读写锁详解
一.读写锁简介 现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁.在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源:但是如果一个线 ...
- 最强Java并发编程详解:知识点梳理,BAT面试题等
本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...
- JAVA IO 类库详解
JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...
- 云时代架构阅读笔记六——Java内存模型详解(二)
承接上文:云时代架构阅读笔记五——Java内存模型详解(一) 原子性.可见性.有序性 Java内存模型围绕着并发过程中如何处理原子性.可见性和有序性这三个特征来建立的,来逐个看一下: 1.原子性(At ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Java 序列化Serializable详解
Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...
- Java String类详解
Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...
- 最新java数组的详解
java中HashMap详解 http://alex09.iteye.com/blog/539545 总结: 1.就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java ...
- 转:Java HashMap实现详解
Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1. HashMap概述: HashMap是基于哈希表的M ...
随机推荐
- 一步一步学习Vue(十)
本篇说一下组件通信的问题,父子组件通信,前面的博客中已有说明,vue也推荐props in,event out:兄弟节点通信如何做呢?官方其实也给出了实现方式,我们以下面的场景来实现一下: 上图中,实 ...
- C#设计模式总结(转)
一.引言 经过这段时间对设计模式的学习,自己的感触还是很多的,因为我现在在写代码的时候,经常会想想这里能不能用什么设计模式来进行重构.所以,学完设计模式之后,感觉它会慢慢地影响到你写代码的思维方式.这 ...
- 【.net 深呼吸】自定义应用程序配置节
实际上,应用程序配置文件 App.config,是由各个节(Configuration Section)组成的,通常,配置节是按功能划分的,比如我们很熟悉的 appSettings.connectio ...
- How to create a jump server in AWS VPC
本来是写的Word文档,给其他国家的同时看的,所以一开始就是英文写的,也没打算翻译成为中文了,顺便抱怨下,网上资料找了很久的资料都没有看到介绍怎么在单机环境下搭建RD Gateway的,写本文的目的是 ...
- [NOIP2009] 靶形数独 骚气的大爆搜
这两天OD留的题是搜索,这个东西,就是历年的NOIP压轴题嘛.做了几道什么斗地主啊啥的,感觉还是这题我还懂点. 这道题的搜(xia)索(da)思路是这样的:预处理出一切能处理的东西. 数独大家都了解吧 ...
- Linux操作系统位数查看
--Linux操作系统位数查看----------------------2014/05/11 查看linux是多少位的几位方法:查看linux机器是32位还是64位的方法: 方法一:file /sb ...
- [INS-30060]:Check for group existence failed
--[INS-30060]:Check for group existence failed -------------------------------------------------2013 ...
- 剑指OFFER——调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 剑指offer书里的版本, ...
- 程序员从技术到项目管理PM--思维转变
对以往所做项目的经验做下总结,作为项目经理首先要对项目负责,思维要做下转变,要从项目全局角度考虑问题: 从个人成就到团队成就. 无论是做管理还是做技术,成就导向意识是优秀员工的基本素质.只有具 ...
- ASP.NET Core 使用Cookie验证身份
ASP.NET Core 1.x提供了通过Cookie 中间件将用户主体序列化为一个加密的Cookie,然后在后续请求中验证Cookie并重新创建主体,并将其分配给HttpContext.User属性 ...