读写锁,我们在多线程中,也是经常遇到。
可以一起读,不可以一起写。也就是可以共患难,不可以共富贵。
怎么才可以做到可以共患难,不可以共富贵呢?其实也不难。四标志位就可以打造最简单的读写锁。
readingReader = 0 正在读的线程数
writingWriter = 0 正在写的线程数
waitingwriter = 0 正在等待写的线程数
preferWriter = true 写入优先
对于读,多少线程都是可以的,
对于写,只允许一个线程
对于其他要写的线程,那就进入等待写队列
有几个冲突是我们需要处理的,那就是 读和写,写和写,写读。
读写:当读的时候获取 读锁,当要获取写多的时候,我们要看读锁是否释放了,或者是否读完毕了。当没有读的线程的时候,就获取了写锁。
写写:当写的时候获取 写锁,当另一个线程也要写的,等待写的数量加一,如果没有写的线程,就轮到他了,如果有那就等待。如果有多个写等待,最后是谁获得这个写锁,就看运气了,这就是非公平锁。
写读:当写的时候获取 写锁,当另一个线程要读的,需要看看是否还有写的线程,如果没有就轮到读锁了。
至于 preferWriter 这个flag 我们来想这么一个情况啊,如果写锁,等待写的线程还有两个,但是某些原因你把写锁解了。接着你要读锁,如果没有这个 preferWriter ,那么明显有等待写的线程,需要等待才好,这样明显不太符合我们的本意,所以就有了这个 preferWriter 当写锁 解开的时候 赋值为false。那么就是读锁优先。
public class ReadWriteLock {private int readingReader = 0;//正在读的线程数private int writingWriter = 0;//正在写的线程数private int waitingWriter = 0;//正在等待写的线程数private boolean preferWriter = true;//如果写入优先 那么就是truepublic synchronized void readLock() throws InterruptedException {while (writingWriter > 0 || (preferWriter && waitingWriter > 0)) {wait();}readingReader++;}public synchronized void readUnlock() {readingReader--;preferWriter = true;notifyAll();}public synchronized void writeLock() throws InterruptedException {waitingWriter++;try {while (readingReader > 0 || writingWriter > 0) {wait();}} finally {waitingWriter--;}writingWriter++;}public synchronized void writeUnlock() {writingWriter--;preferWriter = false;notifyAll();}}
public class ReadThread extends Thread {private final Data data;public ReadThread(Data data) {this.data = data;}@Overridepublic void run() {super.run();try {while (true) {char[] readBuf = data.read();System.out.println(Thread.currentThread().getName() + "-reads-" + String.valueOf(readBuf));}} catch (InterruptedException e) {e.printStackTrace();}}}
public class WriteThread extends Thread{private final Data data;private Random random = new Random();private String filter;private int index = 0;public WriteThread(Data data,String filter) {this.data = data;this.filter = filter;}@Overridepublic void run() {super.run();try {while (true){char c = nextChar();data.writee(c);Thread.sleep(random.nextInt(1000));}}catch (InterruptedException e){}}private char nextChar() {char c = filter.charAt(index);index++;if(index>=filter.length()){index = 0;}return c;}}
public class Data {private final ReadWriteLock lock = new ReadWriteLock();private final char[] buffer;public Data(int size) {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 writee(char c) throws InterruptedException {lock.writeLock();try {doWrite(c);}finally {lock.writeUnlock();}}private void doWrite(char c) {for (int i = 0; i < buffer.length; i++) {buffer[i] = c;slowly();}}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 slowly() {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}
public class Main {public static void main(String[] args) {Data data = new Data(10);new ReadThread(data).start();new ReadThread(data).start();new ReadThread(data).start();new ReadThread(data).start();new ReadThread(data).start();new ReadThread(data).start();new WriteThread(data,"ABCDEF").start();new WriteThread(data,"abcdef").start();}}
