读写锁:多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。即:读的时候不允许写,写的时候不允许读,可以同时读。
synchronized关键字和普通的Lock构造的锁,会造成读与读之间的互斥,因此读写锁可提高性能。
例子1:三个线程同时对一个共享数据进行读写。
importjava.util.Random;
importjava.util.concurrent.locks.ReadWriteLock;
importjava.util.concurrent.locks.ReentrantReadWriteLock;
publicclassReadWriteLockTest {
publicstaticvoidmain(String[] args) {
finalQueue queue =newQueue();
for(inti = 0; i < 3; i++) {
newThread() {
publicvoidrun() {
while(true) {
queue.get();
}
}
}.start();
newThread() {
publicvoidrun() {
while(true) {
queue.put(newRandom().nextInt(10000));
}
}
}.start();
}
}
}
classQueue {
PRivateObjectdata=null;// 共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
ReadWriteLockrwl=newReentrantReadWriteLock();
publicvoidget() {
rwl.readLock().lock();
try{
System.out.println(Thread.currentThread().getName() +" be ready to read data!");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName() +" have read data :"+data);
}catch(InterruptedException e) {
e.printStackTrace();
}finally{
rwl.readLock().unlock();
}
}
publicvoidput(Object data) {
rwl.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName() +" be ready to write data!");
Thread.sleep((long) (Math.random() * 1000));
this.data= data;
System.out.println(Thread.currentThread().getName() +" have write data: "+ data);
}catch(InterruptedException e) {
e.printStackTrace();
}finally{
rwl.writeLock().unlock();
}
}
}
例子2:缓存实例
importjava.util.HashMap;
importjava.util.Map;
importjava.util.concurrent.locks.ReadWriteLock;
importjava.util.concurrent.locks.ReentrantReadWriteLock;
publicclassCacheDemo {
privatestaticMap<String, Object>cache=newHashMap<String, Object>();
privateReadWriteLockrwl=newReentrantReadWriteLock();
publicObject getData(String key) {
// 当线程开始读时,首先开始加上读锁
rwl.readLock().lock();
Object value =null;
try{
value =cache.get(key);
// 判断是否存在值
if(value ==null) {
// 在开始写之前,首先要释放读锁,否则写锁无法拿到
rwl.readLock().unlock();
// 获取写锁开始写数据
rwl.writeLock().lock();
try{
// 再次判断该值是否为空,因为如果两个写线程都阻塞在这里,
// 当一个线程被唤醒后value的值为null则进行数据加载,当另外一个线程也被唤醒如果不判断就会执行两次写
if(value ==null) {
value ="";// query数据库
cache.put(key, value);
}
}finally{
rwl.writeLock().unlock();// 释放写锁
}
rwl.readLock().lock();// 写完之后降级为读锁
}
}finally{
rwl.readLock().unlock();// 释放读锁
}
returnvalue;
}
}