【Read-Write Lock模式】当线程读取实例的状态时,实例的状态不会发生变化。实例的状态仅在线程执行“写入”操作时才会发生变化。在Read-Write Lock模式中,读取操作和写入操作是分开考虑的。在执行读取操作之前,线程必须获取用于读取的锁。而在执行写入操作之前,线程必须获取用于希尔的锁。
由于当线程执行读取操作时,实例的状态不会发生变化,所以多个线程可以同时读取。但在读取时,不可以写入。
当线程执行写入操作时,实例的状态就会发生变化。因此当有一个线程正在写入时,其他线程不可以读取或写入。
【示例程序】
名字 | 说明 |
Main | 测试程序行为的类 |
Data | 可以读写的类 |
WriterThread | 表示写入线程的类 |
ReadThread | 表示读取线程的类 |
ReadWriteLock | 提供读写锁的类 |
Main类
public class Main {
public static void main(String[] args) {
Data data = new Data(10);
new ReaderThread(data).start();
new ReaderThread(data).start();
new ReaderThread(data).start();
new ReaderThread(data).start();
new ReaderThread(data).start();
new ReaderThread(data).start();
new WriterThread(data, "ABCDEFGHIJKLMN").start();
new WriterThread(data, "abcdefghijklmn").start();
}
}
Data类
public class Data {
private final char[] buffer;
private final ReadWriteLock lock = new ReadWriteLock();
public Data(int size) {
this.buffer = new char[size];
for(int i=0;i<buffer.length;i++){
buffer[i] = '*';
}
}
public char[] read() throws InterruptedException {
lock.readLock();
try {
return doRead();
} finally {
lock.readUnlock();
}
}
public void write(char c) throws InterruptedException {
lock.writeLock();
try {
doWrite(c);
} finally {
lock.writeUnlock();
}
}
private char[] doRead() {
char[] newbuf = new char[buffer.length];
for(int i=0;i<buffer.length;i++) {
newbuf[i]=buffer[i];
}
slowly();
return newbuf;
}
private void doWrite(char c) {
for(int i=0;i<buffer.length;i++) {
buffer[i]=c;
slowly();
}
}
private void slowly() {
try {
Thread.sleep(50);
} catch(InterruptedException e){}
}
}
WriterThread类
public class WriterThread extends Thread {
private static final Random random = new Random();
private final Data data;
private final String filler;
private int index = 0;
public WriterThread(Data data, String filler) {
this.data=data;
this.filler=filler;
}
public void run() {
try {
while(true){
char c = nextchar();
data.write(c);
Thread.sleep(random.nextInt(3000));
}
}catch(InterruptedException e){}
}
private char nextchar() {
char c=filler.charAt(index);
index++;
if(index>=filler.length()){
index=0;
}
return c;
}
}
ReaderThread类
public class ReaderThread extends Thread {
private final Data data;
public ReaderThread(Data data){
this.data=data;
}
public void run(){
try{
while(true){
char[] readbuf=data.read();
System.out.println(Thread.currentThread().getName()+" reads "+String.valueOf(readbuf));
}
}catch(InterruptedException e){}
}
}
ReadWriterLock类
public class ReadWriteLock {
private int readingReaders = 0;//实际正在读取中的线程个数
private int waitingWriters = 0;//正在等待写入的线程个数
private int writingReaders = 0;//实际正在写入的线程个数
private boolean preferWriter = true;//若写入优先,则为true
public synchronized void readLock() throws InterruptedException {
while(writingReaders > 0 || (preferWriter && waitingWriters > 0)) {
wait();
}
readingReaders++;
}
public synchronized void readUnlock() {
readingReaders--;
preferWriter = true;
notifyAll();
}
public synchronized void writeLock() throws InterruptedException {
waitingWriters++;
try {
while(readingReaders>0||writingReaders>0){
wait();
}
}finally{
waitingWriters--;
}
writingReaders++;
}
public synchronized void writeUnlock() {
writingReaders--;
preferWriter = false;
notifyAll();
}
}
【守护条件的确认】
readLock方法
在线程开始实际的读取操作之前,readLock方法就会被调用。当线程从该方法返回后,便可开始执行实际的读取操作。
当线程开始执行实际的读取操作时,有其他线程正在执行读取操作也没关系,但不可以存在正在执行写入操作的线程。因为当有线程正在执行写入操作时,如果开始执行读取操作,便会引起read-write conflict。因此守护条件是“没有线程正在执行写入操作”。
writingReaders<=0
writeLock方法
在线程开始实际的写入操作之前,writeLock方法就会被调用。当线程从该方法返回后,便可开始执行实际的写入操作。
如果有线程正在执行读取操作,便会引起read-write conflict;如果有线程正在执行写入操作,便会引起write-write conflict。因此守护条件为“没有线程正在执行读取操作或写入操作”
readingReaders<=0&&writingReaders<=0
【Read-Write Lock模式中登场的角色】
1Reader读者
Reader角色对SharedResource角色执行read操作。
2.Writer写者
Writer角色对SharedResource角色执行write操作。
3.ShareRescource共享资源
ShareRescource角色表示的是Reader角色和Writer角色二者共享的资源。ShareRescource角色提供不修改内部状态的操作read和修改内部状态的操作write。
4.ReadWriteLock读写锁
ReadWriteLock角色提供了ShareRescource角色实现read操作和write操作时所需的锁。
【锁的含义】
synchronized可以用于获取实例的锁。Java的每一个实例都持有一个锁,但同一个锁不可以由两个以上的线程同时获取。这是所谓的物理锁。
用于读取的锁和用于写入的锁所指的锁与使用synchronized获取的锁是不一样的。逻辑锁。开发人员可以通过修改ReadWriteLock来改变锁的运行。