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锁
    原文地址: http://www.cnblogs.com/grefr/p/6095021.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞