详见: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, 060, 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, 11, TimeUnit.SECONDS);
    service.scheduleAtFixedRate(readTask2, 21, TimeUnit.SECONDS);
    service.scheduleAtFixedRate(readTask3, 31, 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 读写锁详解的更多相关文章

  1. ReentrantReadWriteLock读写锁详解

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

  2. 最强Java并发编程详解:知识点梳理,BAT面试题等

    本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...

  3. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

  4. 云时代架构阅读笔记六——Java内存模型详解(二)

    承接上文:云时代架构阅读笔记五——Java内存模型详解(一) 原子性.可见性.有序性 Java内存模型围绕着并发过程中如何处理原子性.可见性和有序性这三个特征来建立的,来逐个看一下: 1.原子性(At ...

  5. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  6. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...

  7. Java String类详解

    Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...

  8. 最新java数组的详解

    java中HashMap详解 http://alex09.iteye.com/blog/539545 总结: 1.就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java ...

  9. 转:Java HashMap实现详解

    Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1.    HashMap概述:    HashMap是基于哈希表的M ...

随机推荐

  1. R读取MySQL数据出现乱码,解决该问题的方法总结

    最终的解决办法直接看 4 我的思路: 我用的都是utf-8编码,电脑系统win7, MySQL-Front进行数据库的可视化. 1.我用的是RStudio,先去设置R的默认编码: Tools→Glob ...

  2. amd和cmd区别

    作者:玉伯 链接:https://www.zhihu.com/question/20351507/answer/14859415 来源:知乎 著作权归作者所有,转载请联系作者获得授权. AMD 是 R ...

  3. Tornado session 插件 pycket 定制时间和时间续租

    功能描述:10分钟用户没有任何操作,跳转到登录页面. 分析:这个功能用session就能实现(由于pycket 的session内容是存储在memcached或者redis里面的.所以,session ...

  4. Akka(16): 持久化模式:PersistentFSM-可以自动修复的状态机器

    前面我们讨论过FSM,一种专门为维护内部状态而设计的Actor,它的特点是一套特殊的DSL能很方便地进行状态转换.FSM的状态转换模式特别适合对应现实中的业务流程,因为它那套DSL可以更形象的描述业务 ...

  5. div模拟textarea文本域轻松实现高度自适应

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. nodejs 文件读取一行

    作者QQ:1095737364    QQ群:123300273     欢迎加入!   废话没有,直接上代码: app.get('/company', function (req, res, nex ...

  7. curl笔记

    -a/--append 上传文件时,附加到目标文件 -A/--user-agent 设置用户代理发送给服务器 -anyauth 可以使用"任何"身份验证方法 -b/--cookie ...

  8. 查看oracle版本信息

    查看oracle的版本信息 (1)用客户端连接到数据库,执行select * from v$instance            查看version项 (2)select * from produc ...

  9. Python二分法查找及变种分析

    基于Python3 普通二分法查找目标值的index 二分法查找的思路很简单,先确定好列表nums的一头start一尾end,中间值middle根据头尾数值之和用地板除法除以2,即(start + e ...

  10. 【技术干货】听阿里云CDN安防技术专家金九讲SystemTap使用技巧

    ​1.简介 SystemTap是一个Linux非常有用的调试(跟踪/探测)工具,常用于Linux 内核或者应用程序的信息采集,比如:获取一个函数里面运行时的变 量.调用堆栈,甚至可以直接修改变量的值, ...