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读写锁的使用<转>的更多相关文章

  1. ReentrantReadWriteLock读写锁的使用

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...

  2. ReentrantReadWriteLock读写锁的使用2

    本文可作为传智播客<张孝祥-Java多线程与并发库高级应用>的学习笔记. 这一节我们做一个缓存系统. 在读本节前 请先阅读 ReentrantReadWriteLock读写锁的使用1 第一 ...

  3. 锁对象-Lock: 同步问题更完美的处理方式 (ReentrantReadWriteLock读写锁的使用/源码分析)

    Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我 ...

  4. Java并发包源码学习系列:ReentrantReadWriteLock读写锁解析

    目录 ReadWriteLock读写锁概述 读写锁案例 ReentrantReadWriteLock架构总览 Sync重要字段及内部类表示 写锁的获取 void lock() boolean writ ...

  5. ReentrantReadWriteLock读写锁简单原理案例证明

    ReentrantReadWriteLock存在原因? 我们知道List的实现类ArrayList,LinkedList都是非线程安全的,Vector类通过用synchronized修饰方法保证了Li ...

  6. ReentrantReadWriteLock读写锁详解

    一.读写锁简介 现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁.在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源:但是如果一个线 ...

  7. java多线程:并发包中ReentrantReadWriteLock读写锁的锁降级模板

    写锁降级为读锁,但读锁不可升级或降级为写锁. 锁降级是为了让当前线程感知到数据的变化. //读写锁 private ReentrantReadWriteLock lock=new ReentrantR ...

  8. java中ReentrantReadWriteLock读写锁的使用

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...

  9. java多线程:ReentrantReadWriteLock读写锁使用

    Lock比传统的线程模型synchronized更多的面向对象的方式.锁和生活似,应该是一个对象.两个线程运行的代码片段要实现同步相互排斥的效果.它们必须用同一个Lock对象. 读写锁:分为读锁和写锁 ...

  10. ReentrantReadWriteLock读写锁的使用1

    本文可作为传智播客<张孝祥-Java多线程与并发库高级应用>的学习笔记. 一个简单的例子 两个线程,一个不断打印a,一个不断打印b public class LockTest { publ ...

随机推荐

  1. jquery判断滚动条是否到底部

    clientHeight:这个元素的高度,占用整个空间的高度,所以,如果一个div有滚动条,那个这个高度则是不包括滚动条没显示出来的下面部分的内容.而只是单纯的DIV的高度. offsetHeight ...

  2. C++ 相关面试题汇总

    多态性与虚函数 (陈维兴教材) (1)所谓多态性就是不同对象在收到相同的消息时,产生不同的动作.直观的说,多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的操作,从而可以使用相同的方式来调 ...

  3. 用C#读取图片的EXIF信息的方法

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Dr ...

  4. html中块注释<!--[if IE]>….<![endif]--> (<!--[if !IE]>||<![endif]

    1. <!--[if !IE]><!--> 除IE外都可识别 <!--<![endif]-->2. <!--[if IE]> 所有的IE可识别 & ...

  5. gsoap

    C++中如何使用gsoap开发WebService 1. 什么是gSOAPgSOAP是一个夸平台的,用于开发Web Service服务端和客户端的工具,在Windows.Linux.MAC OS和UN ...

  6. 谷歌Gmail 加速

    由于某些原因的限制,我们使用谷歌的Gmail服务时,网络加载总是很慢!如下修复 一:修改hosts文件 ping -c g.cn      得到ip地址 在hosts文件里面 添加  上面的 ip地址 ...

  7. 微信小程序 - 展开收缩列表

    代码源自于:微信小程序示例官方 index.wxml <block wx:for-items="{{list}}" wx:key="{{item.id}}" ...

  8. openerp domain 規則

    oe中的domain多用于自定义搜索条件. domain中的单个条件是一个三个元素组成的元组.第一个是对象的一个column,也就是字段名:第二个是比较运算符``=, !=, & gt;, & ...

  9. Mac安装Myeclipse2015开发环境

    1.下载Myeclipse2015 链接: http://pan.baidu.com/s/1jHe8mFk 密码: qgeb 下载下来后,在安装的时候需要自己设置下安装目标,不然在破解的时候不是太好找 ...

  10. bash算术求值和errexit陷阱

    原文:https://www.technovelty.org//linux/bash-arithmetic-evaluation-and-errexit-trap.html 在 "traps ...