package cn.javaious.concurrence;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
final Queue3 q3 = new Queue3();
for(int i=0;i<3;i++) {
new Thread() {
public void run() {
for(;;) {
q3.get();
}
}
}.start();
new Thread() {
public void run() {
for(;;) {
q3.put(new Random().nextInt(1000));
}
};
}.start();
}
}
}
class Queue3 {
private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读数据
ReadWriteLock rwl = new ReentrantReadWriteLock();
public void get() {
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) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
rwl.readLock().unlock();
}
}
public void put(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 read data :"+data);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
rwl.writeLock().unlock();
}
}
}
操作系统中也有读写者经典问题:该问题最早由Dijkstra提出,用以演示他提出的信号量机制。要求设计在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
//已知mutex,wrt都是二进制信号量,初始化为1,readcount是读者的个数
//写者
do
{
wait(wrt);
临界区 //互斥共享的资源称为临界资源,在程序中对临界资源访问的代码称为临界区。
signal(wrt);
}while(true);
//读者
do
{
wait(mutex);
readcount++;
if(readcount==1)
wait(wrt);
signal(mutex);
wait(mutex);
readcount--;
if(readcount==0)
signal(wrt);
signal(mutex);
}while(true);
读写锁api上的经典例子:
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock(); //进来就开始读,上读锁,不允许写
if (!cacheValid) { //缓存不可用
// Must release read lock before acquiring write lock
rwl.readLock().unlock(); //缓存不可用,立马释放写锁,等待数据
rwl.writeLock().lock(); //上写锁,不允许读
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) { //重新检查缓存状态,rwl.writeLock().lock()会造成线程阻塞,第一个线程成功写入后,其后阻塞的线程需要再次判断
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock(); //降级通过在释放写锁之前获取读锁(锁降级)
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read 释放写锁,保持读锁状态
}
}
try {
use(data);
} finally {
rwl.readLock().unlock(); //释放读锁
}
}
}
关于锁降级,可以参考: http://www.cnblogs.com/hzhuxin/archive/2012/11/01/2749341.html