Definition
读写锁包含一对相关的锁,读锁用于只读操作,写锁用于写操作。读锁可能由多个读线程同时运行,写锁是唯一的。
Direction
1、读锁和写锁之间是互斥的,同一时间只能有一个在运行。但是可以有多个线程同时读取数据。
2、写入数据之前必须重新确认(ReCheck)状态,因为其他的线程可能会拿到写锁再一次修改我们已经修改过的值。这是因为前一个线程拿到写锁之后,后面的线程会被阻塞。当前一个线程释放写锁之后,被阻塞的线程会继续运行完成被阻塞的部分代码,所以才会出现这样的情况。
3、当某一个线程上了写锁之后,自己仍然可以上读锁,之后在释放写锁,这是一种降级(Downgrade)的处理方法。
Method
读写锁(ReadWriteLock)包含如下两个方法:
1.读锁
Lock readLock()
2.写锁
Lock writeLock()
Example
以下代码在开始读数据的时候上读锁,当有一个线程发现没有数据时,释放读锁,上写锁,开始写入数据。
数据写入完成后释放写锁,并还原成读锁,实现了简单的读和写之间的互斥。
示例代码:
private ReadWriteLock rwl = new ReentrantReadWriteLock();//定义读写锁 public Object getData(String key){ //使用读写锁的基本结构 rwl.readLock().lock(); Object value = null; try{ value = cache.get(key); if(value == null){ rwl.readLock().unlock(); rwl.writeLock().lock(); try{ // Recheck state because another thread might have // acquired write lock and changed state before we did. if(value == null){ value = "aaaa";//写入数据 } }finally{ rwl.writeLock().unlock(); } rwl.readLock().lock(); } }finally{ rwl.readLock().unlock(); } return value; }
读写锁的完整使用示例:
1 public class Test { 2 public static void main(String[] args) { 3 final Queue q = new Queue(); 4 for(int i=0;i<3;i++) 5 { 6 new Thread(){ 7 public void run(){ 8 while(true){ 9 q.get(); 10 } 11 } 12 }.start(); 13 14 new Thread(){ 15 public void run(){ 16 while(true){ 17 q.put(new Random().nextInt(10000)); 18 } 19 } 20 }.start(); 21 } 22 } 23 } 24 25 class Queue{ 26 private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。 27 ReadWriteLock rwl = new ReentrantReadWriteLock(); 28 public void get(){ 29 rwl.readLock().lock(); 30 try { 31 System.out.println(Thread.currentThread().getName() + " be ready to read data!"); 32 Thread.sleep((long)(Math.random()*1000)); 33 System.out.println(Thread.currentThread().getName() + "have read data :" + data); 34 } catch (InterruptedException e) { 35 e.printStackTrace(); 36 }finally{ 37 rwl.readLock().unlock(); 38 } 39 } 40 41 public void put(Object data){ 42 rwl.writeLock().lock(); 43 try { 44 System.out.println(Thread.currentThread().getName() + " be ready to write data!"); 45 Thread.sleep((long)(Math.random()*1000)); 46 this.data = data; 47 System.out.println(Thread.currentThread().getName() + " have write data: " + data); 48 } catch (InterruptedException e) { 49 e.printStackTrace(); 50 }finally{ 51 rwl.writeLock().unlock(); 52 } 53 } 54 }
部分输出结果如下:
Thread-0 be ready to read data! Thread-2 be ready to read data! Thread-4 be ready to read data! Thread-4have read data :null Thread-0have read data :null Thread-2have read data :null Thread-3 be ready to write data! Thread-3 have write data: 9763 Thread-3 be ready to write data! Thread-3 have write data: 5187 Thread-3 be ready to write data! Thread-3 have write data: 2135 Thread-1 be ready to write data! Thread-1 have write data: 180 Thread-1 be ready to write data! Thread-1 have write data: 5979 Thread-1 be ready to write data! Thread-1 have write data: 9495 Thread-1 be ready to write data! Thread-1 have write data: 6363 Thread-1 be ready to write data! Thread-1 have write data: 31 Thread-1 be ready to write data! Thread-1 have write data: 7530 Thread-1 be ready to write data! Thread-1 have write data: 1354 Thread-5 be ready to write data! Thread-5 have write data: 3580 Thread-5 be ready to write data! Thread-5 have write data: 5534 Thread-5 be ready to write data! Thread-5 have write data: 2522 Thread-5 be ready to write data! Thread-5 have write data: 2926 Thread-4 be ready to read data! Thread-0 be ready to read data! Thread-2 be ready to read data! Thread-2have read data :2926 Thread-0have read data :2926 Thread-4have read data :2926