ReentrantReadWriteLock读写锁的使用<转>
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!
ReentrantReadWriteLock会使用两把锁来解决问题,一个读锁,一个写锁
线程进入读锁的前提条件:
没有其他线程的写锁,
没有写请求或者有写请求,但调用线程和持有锁的线程是同一个
线程进入写锁的前提条件:
没有其他线程的读锁
没有其他线程的写锁
到ReentrantReadWriteLock,首先要做的是与ReentrantLock划清界限。它和后者都是单独的实现,彼此之间没有继承或实现的关系。然后就是总结这个锁机制的特性了:
(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异常。
下面看一个读写锁的例子:

1 package com.thread;
2
3 import java.util.Random;
4 import java.util.concurrent.locks.ReentrantReadWriteLock;
5
6 public class ReadWriteLockTest {
7 public static void main(String[] args) {
8 final Queue3 q3 = new Queue3();
9 for(int i=0;i<3;i++)
10 {
11 new Thread(){
12 public void run(){
13 while(true){
14 q3.get();
15 }
16 }
17
18 }.start();
19 }
20 for(int i=0;i<3;i++)
21 {
22 new Thread(){
23 public void run(){
24 while(true){
25 q3.put(new Random().nextInt(10000));
26 }
27 }
28
29 }.start();
30 } 31 }
32 }
33
34 class Queue3{
35 private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
36 private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
37 public void get(){
38 rwl.readLock().lock();//上读锁,其他线程只能读不能写
39 System.out.println(Thread.currentThread().getName() + " be ready to read data!");
40 try {
41 Thread.sleep((long)(Math.random()*1000));
42 } catch (InterruptedException e) {
43 e.printStackTrace();
44 }
45 System.out.println(Thread.currentThread().getName() + "have read data :" + data);
46 rwl.readLock().unlock(); //释放读锁,最好放在finnaly里面
47 }
48
49 public void put(Object data){
50
51 rwl.writeLock().lock();//上写锁,不允许其他线程读也不允许写
52 System.out.println(Thread.currentThread().getName() + " be ready to write data!");
53 try {
54 Thread.sleep((long)(Math.random()*1000));
55 } catch (InterruptedException e) {
56 e.printStackTrace();
57 }
58 this.data = data;
59 System.out.println(Thread.currentThread().getName() + " have write data: " + data);
60
61 rwl.writeLock().unlock();//释放写锁
62 }
63 }


Thread-0 be ready to read data!
Thread-1 be ready to read data!
Thread-2 be ready to read data!
Thread-0have read data :null
Thread-2have read data :null
Thread-1have read data :null
Thread-5 be ready to write data!
Thread-5 have write data: 6934
Thread-5 be ready to write data!
Thread-5 have write data: 8987
Thread-5 be ready to write data!
Thread-5 have write data: 8496

下面使用读写锁模拟一个缓存器:

1 package com.thread;
2
3 import java.util.HashMap;
4 import java.util.Map;
5 import java.util.concurrent.locks.ReadWriteLock;
6 import java.util.concurrent.locks.ReentrantReadWriteLock;
7
8 public class CacheDemo {
9 private Map<String, Object> map = new HashMap<String, Object>();//缓存器
10 private ReadWriteLock rwl = new ReentrantReadWriteLock();
11 public static void main(String[] args) {
12
13 }
14 public Object get(String id){
15 Object value = null;
16 rwl.readLock().lock();//首先开启读锁,从缓存中去取
17 try{
18 value = map.get(id);
19 if(value == null){ //如果缓存中没有释放读锁,上写锁
20 rwl.readLock().unlock();
21 rwl.writeLock().lock();
22 try{
23 if(value == null){
24 value = "aaa"; //此时可以去数据库中查找,这里简单的模拟一下
25 }
26 }finally{
27 rwl.writeLock().unlock(); //释放写锁
28 }
29 rwl.readLock().lock(); //然后再上读锁
30 }
31 }finally{
32 rwl.readLock().unlock(); //最后释放读锁
33 }
34 return value;
35 }
36
37 }

转自 http://www.cnblogs.com/liuling/archive/2013/08/21/2013-8-21-03.html
ReentrantReadWriteLock读写锁的使用<转>的更多相关文章
- ReentrantReadWriteLock读写锁的使用
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...
- ReentrantReadWriteLock读写锁的使用2
本文可作为传智播客<张孝祥-Java多线程与并发库高级应用>的学习笔记. 这一节我们做一个缓存系统. 在读本节前 请先阅读 ReentrantReadWriteLock读写锁的使用1 第一 ...
- 锁对象-Lock: 同步问题更完美的处理方式 (ReentrantReadWriteLock读写锁的使用/源码分析)
Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我 ...
- Java并发包源码学习系列:ReentrantReadWriteLock读写锁解析
目录 ReadWriteLock读写锁概述 读写锁案例 ReentrantReadWriteLock架构总览 Sync重要字段及内部类表示 写锁的获取 void lock() boolean writ ...
- ReentrantReadWriteLock读写锁简单原理案例证明
ReentrantReadWriteLock存在原因? 我们知道List的实现类ArrayList,LinkedList都是非线程安全的,Vector类通过用synchronized修饰方法保证了Li ...
- ReentrantReadWriteLock读写锁详解
一.读写锁简介 现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁.在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源:但是如果一个线 ...
- java多线程:并发包中ReentrantReadWriteLock读写锁的锁降级模板
写锁降级为读锁,但读锁不可升级或降级为写锁. 锁降级是为了让当前线程感知到数据的变化. //读写锁 private ReentrantReadWriteLock lock=new ReentrantR ...
- java中ReentrantReadWriteLock读写锁的使用
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...
- java多线程:ReentrantReadWriteLock读写锁使用
Lock比传统的线程模型synchronized更多的面向对象的方式.锁和生活似,应该是一个对象.两个线程运行的代码片段要实现同步相互排斥的效果.它们必须用同一个Lock对象. 读写锁:分为读锁和写锁 ...
- ReentrantReadWriteLock读写锁的使用1
本文可作为传智播客<张孝祥-Java多线程与并发库高级应用>的学习笔记. 一个简单的例子 两个线程,一个不断打印a,一个不断打印b public class LockTest { publ ...
随机推荐
- PHP的错误处理方式(开发和上线)
对于PHP开发人员来说,一旦某个产品投入使用.应该马上将 display_errors选项关闭.以免由于这些错误所透露的路径.数据库连接.数据表等信息而遭到黑客攻击. 可是.不论什么一个产品在投入使用 ...
- <The Art of Readable Code> 笔记二 (上)
第2章 封装信息到名字 (Packing information into names) 2.1 use specific words GetPage() 不如 FetchPage() 和 Dow ...
- Spring MVC过滤器-登录过滤
以下代码是继承OncePerRequestFilter实现登录过滤的代码: package com.test.spring.filter; import java.io.IOException; im ...
- MySQL 5.1参数
MySQL 5.1.73参数 Variable_name Valueauto_increment_increment 1auto_increment_offset 1autocommit ONa ...
- 百度地图总结第二篇--POI检索功能
简单介绍: 眼下百度地图SDK所集成的检索服务包含:POI检索.公交信息查询.线路规划.地理编码.行政区边界数据检索.在线建议查询.短串分享(包含POI搜索结果分享.驾车/公交/骑行/步行路线规划分享 ...
- JavaWeb 绝对路径与相对路径
JavaWeb 绝对路径与相对路径 CreateTime--2018年4月14日16:51:19 Author:Marydon 8.1 绝对路径 web项目不可能使用绝对路径,因为: 以文件的引用 ...
- [MSP430]入门之中的一个 总体认识
这是由TI公司推出的一款比較单片机, 相对stm32来说简单些, 由于它是16位的, 所以我们在学习中可能也会像51一样, 直接操纵寄存器. TI设计这款单片机的初衷是, 让它用于低功耗的嵌入式设 ...
- spring AOP编程--AspectJ注解方式
1. AOP 简介 AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, ...
- BeanUtils的介绍使用
BeanUtils工具 在实际的开发中我们经常需要将用户的录入的数据进行封装为对象,那么如果使用反射和内省技术就会变得吃力.因此本节主要给大家讲解一个开源的操作JavaBean的一个工具即BeanUt ...
- Ruby 和 Python 分析器是如何工作的?
你好! 我作为一名编写Ruby profiler的先驱,我想对现有的Ruby和Python profiler如何工作进行一次调查. 这也有助于回答很多人的问题:“你怎么写一个profiler?” 在这 ...