读写锁:多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。即:读的时候不允许写,写的时候不允许读,可以同时读。
synchronized关键字和普通的Lock构造的锁,会造成读与读之间的互斥,因此读写锁可提高性能。
例子1:三个线程同时对一个共享数据进行读写。
1 import java.util.Random; 2 import java.util.concurrent.locks.ReadWriteLock; 3 import java.util.concurrent.locks.ReentrantReadWriteLock; 4 5 public class ReadWriteLockTest { 6 public static void main(String[] args) { 7 final Queue queue = new Queue(); 8 for (int i = 0; i < 3; i++) { 9 new Thread() {10 public void run() {11 while (true) {12 queue.get();13 }14 }15 16 }.start();17 18 new Thread() {19 public void run() {20 while (true) {21 queue.put( new Random().nextInt(10000));22 }23 }24 25 }.start();26 }27 28 }29 }30 31 class Queue {32 private Object data = null; // 共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。33 ReadWriteLock rwl = new ReentrantReadWriteLock();34 35 public void get() {36 rwl.readLock().lock();37 try {38 System. out.println(Thread.currentThread().getName() + " be ready to read data!");39 Thread. sleep((long) (Math. random() * 1000));40 System. out.println(Thread.currentThread().getName() + " have read data :" + data);41 } catch (InterruptedException e) {42 e.printStackTrace();43 } finally {44 rwl.readLock().unlock();45 }46 }47 48 public void put(Object data) {49 50 rwl.writeLock().lock();51 try {52 System. out.println(Thread.currentThread().getName() + " be ready to write data!");53 Thread. sleep((long) (Math. random() * 1000));54 this.data = data;55 System. out.println(Thread.currentThread().getName() + " have write data: " + data);56 } catch (InterruptedException e) {57 e.printStackTrace();58 } finally {59 rwl.writeLock().unlock();60 }61 62 }63 }
例子2:缓存实例
1 import java.util.HashMap; 2 import java.util.Map; 3 import java.util.concurrent.locks.ReadWriteLock; 4 import java.util.concurrent.locks.ReentrantReadWriteLock; 5 6 public class CacheDemo { 7 8 private static Map<String, Object> cache = new HashMap<String, Object>(); 9 10 private ReadWriteLock rwl = new ReentrantReadWriteLock();11 12 public Object getData(String key) {13 // 当线程开始读时,首先开始加上读锁14 rwl.readLock().lock();15 Object value = null;16 try {17 value = cache.get(key);18 // 判断是否存在值19 if (value == null) {20 // 在开始写之前,首先要释放读锁,否则写锁无法拿到21 rwl.readLock().unlock();22 // 获取写锁开始写数据23 rwl.writeLock().lock();24 try {25 // 再次判断该值是否为空,因为如果两个写线程都阻塞在这里,26 // 当一个线程被唤醒后value的值为null则进行数据加载,当另外一个线程也被唤醒如果不判断就会执行两次写 27 if (value == null) {28 value = "" ; // query 数据库29 cache.put(key, value);30 }31 } finally {32 rwl.writeLock().unlock(); // 释放写锁33 }34 rwl.readLock().lock(); // 写完之后降级为读锁35 }36 } finally {37 rwl.readLock().unlock(); // 释放读锁38 }39 40 return value;41 }42 43 }