zoukankan      html  css  js  c++  java
  • 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(" ");      
          }
          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异常.

  • 相关阅读:
    IDEA常用快捷键整理(Mac OS X版本)
    转发与重定向的区别
    关于Navicat远程连接远程服务器的mysql 报错问题
    关于mac 系统如何通过终端 连接linux服务器 并传文件!
    Java中String和byte[]间的转换浅析
    选择排序Java版
    插入排序Java版
    JS知识点
    Excel 函数
    垂直滚动公告板
  • 原文地址:https://www.cnblogs.com/grefr/p/6095021.html
Copyright © 2011-2022 走看看