来源于:《java多线程设计模式》一书
本例的类结构图:
2.Data类:
package read.write.pattern;
/**
* 读者与写者共同要访问的数据类
* @author lxb
*
*/
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] = '*';
}
}
/**
* 读者逻辑
* 1.先获取读者锁,读读之间不存在互斥,但读写之间存在互斥关系
* 2.在获取读者锁之前需要先判断是否有写者正在进行写操作,如果有则进行等待,否则直接读
* @return
* @throws InterruptedException
*/
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) {
}
}
}
3.读者线程类:
package read.write.pattern;
/**
* 读者线程
* @author lxb
*
*/
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) {
}
}
}
4.写者线程:
package read.write.pattern;
import java.util.Random;
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;
}
}
5.自定义锁:
package read.write.pattern;
/**
* 自定义读写锁
* @author lxb
*
*/
public final class ReadWriteLock {
private int readingReaders = 0; // (A)...实际正在读取的执行绪数量
private int waitingWriters = 0; // (B)...正在等待写入的执行绪数量
private int writingWriters = 0; // (C)...实际正在写入的执行绪数量
private boolean preferWriter = true; // 写入优先的话,值为true
/**
* 获取读者锁
* 如果已经有写者进行写入操作时进行等待
*
* @throws InterruptedException
*/
public synchronized void readLock() throws InterruptedException {
while (writingWriters > 0 || (preferWriter && waitingWriters > 0)) {
wait();
}
readingReaders++; // (A)实际正在读取的线程数量加1
}
/**
* 释放读者锁
*/
public synchronized void readUnlock() {
readingReaders--; // (A)实际正在读取的线程数量减1
preferWriter = true;
notifyAll();
}
/**
* 1.如果有写者进行写入时进行等待,写写之间互斥
* 2.如果有读者正在进行读操作时,等待,写读之间互斥
*
* @throws InterruptedException
*/
public synchronized void writeLock() throws InterruptedException {
waitingWriters++; // (B)正在等待写入的线程数量加1
try {
while (readingReaders > 0 || writingWriters > 0) {
wait();
}
} finally {
waitingWriters--; // (B)正在等待写入的线程数量减1
}
writingWriters++; // (C)实际正在写入的线程数量加1
}
/**
* 释放写者锁
*/
public synchronized void writeUnlock() {
writingWriters--; // (C)实际正在写入的线程数量减
preferWriter = false;
notifyAll();
}
}
6.测试类:模拟多个读者与多个写者:
package read.write.pattern;
/**
* 模拟读者--写者模式
* @author lxb
*(1)允许多个读者同时执行读操作;
*(2)不允许读者、写者同时操作;
*(3)不允许多个写者同时操作。
*/
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, "ABCDEFGHIJKLMNOPQRSTUVWXYZ").start();
new WriterThread(data, "abcdefghijklmnopqrstuvwxyz").start();
}
}