学生们正在一起看老师在黑板上写的板书,这时,老师想擦掉板书,再写新的内容.而学生们说道:"老师,我们还没看完,don't wipe it!"于是,老师会等待大家看完.
在线程"读取"实例的状态时,实例的状态不会发生变化.实例的状态仅在线程"写入"时才会发生变化.
ReadWriteLock类:
public class ReadWriteLock {
private int readingReaders = 0; //正在读取的线程数量
private int writingWriters = 0; //正在写入的线程数量
public synchronized void readLock() throws InterruptedException {
while (writingWriters > 0) { //如果有线程在执行写入,等待.
wait();
}
readingReaders++; //实际在读取的线程+1
}
public synchronized void unReadLock() {
readingReaders--; //实际读取线程-1
notifyAll();
}
public synchronized void writeLock() throws InterruptedException {
while (writingWriters > 0 || readingReaders > 0) { //如果有线程正在写入,或者在读取 等待
wait();
}
writingWriters++; //正在写入的线程+1
}
public synchronized void unWriteLock() {
writingWriters--; //正在写入的线程-1
notifyAll();
}
}
该类提供了用于读取的锁和用于写入的锁.;
为了保证安全性,我们必须防止两种冲突.
1.read和write的冲突
2.write和write的冲突.
因为read和read不存在冲突,所以我们不需要考虑他们.
为了防止冲突,我们来思考一下获取用于读取的锁和用于写入的锁的条件.这里存在4种情况.
1.当线程想获取用于读取的锁时.
(1)如果有线程正在写入,等待.
because:会引起read write conflict.
(2)如果有线程正在读取.无需等待.
because:read read 不会引起conflict.
2.当线程想要获取用于写入的锁时
(3)如果有线程正在写入,等待.
because:会引起write write conflict.
(4)如果有现成正在读取,等待.
because:会引起read write conflict.
Data类:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Data {
private final char[] buffer;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); //这个其实是java.util.concurrent.locks写好的读写锁类,可以直接调用 不用自己写啦.
private final Lock readLock = lock.readLock();//读锁
private final Lock writeLock = lock.writeLock();//写锁
private final ReadWriteLock readWriteLock = 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 {
readWriteLock.readLock();
try {
return doRead();
} finally {
readWriteLock.unReadLock();
}
}
public void write(char c) throws InterruptedException {
readWriteLock.writeLock();
try {
doWrite(c);
} finally {
readWriteLock.unWriteLock();
}
}
private char[] doRead() {
char[] newbuf = new char[buffer.length];
for (int i = 0; i < newbuf.length; i++) {
newbuf[i] = buffer[i];
}
slowly();
return newbuf;
}
private void slowly() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void doWrite(char c) {
for (int i = 0; i < buffer.length; i++) {
buffer[i] = c;
slowly();
}
}
}
WriterThread类:
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);
System.out.println(Thread.currentThread().getName()+"write"+c);
Thread.sleep(random.nextInt(3000));
}
} catch (InterruptedException e) {
// TODO: handle exception
}
}
private char nextchar() {
char c = filler.charAt(index);
index++;
if (index >= filler.length()) {
index = 0;
}
return c;
}
}
ReadThread类:
public class ReaderThread extends Thread {
private final Data data;
public ReaderThread(Data data) {
this.data = data;
}
public void run() {
try {
while (true) {
char[] read = data.read();
System.out.println(Thread.currentThread().getName()+" reads "+String.valueOf(read));
Thread.sleep(1000);
}
} catch (InterruptedException e) {
// TODO: handle exception
}
}
}
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, "abcdefghijklmnopqrstuvwxyz").start();
new WriterThread(data, "ABCDEFGHIJKLMNOPQRSTUVWXYZ").start();
}
}