读写锁,我们在多线程中,也是经常遇到。

    可以一起读,不可以一起写。也就是可以共患难,不可以共富贵。

    怎么才可以做到可以共患难,不可以共富贵呢?其实也不难。四标志位就可以打造最简单的读写锁。

    readingReader = 0 正在读的线程数
    writingWriter = 0 正在写的线程数
    waitingwriter = 0 正在等待写的线程数

    preferWriter = true 写入优先

    对于读,多少线程都是可以的,
    对于写,只允许一个线程
    对于其他要写的线程,那就进入等待写队列

    有几个冲突是我们需要处理的,那就是 读和写,写和写,写读。

    读写:当读的时候获取 读锁,当要获取写多的时候,我们要看读锁是否释放了,或者是否读完毕了。当没有读的线程的时候,就获取了写锁。

    写写:当写的时候获取 写锁,当另一个线程也要写的,等待写的数量加一,如果没有写的线程,就轮到他了,如果有那就等待。如果有多个写等待,最后是谁获得这个写锁,就看运气了,这就是非公平锁。

    写读:当写的时候获取 写锁,当另一个线程要读的,需要看看是否还有写的线程,如果没有就轮到读锁了。

    至于 preferWriter 这个flag 我们来想这么一个情况啊,如果写锁,等待写的线程还有两个,但是某些原因你把写锁解了。接着你要读锁,如果没有这个 preferWriter ,那么明显有等待写的线程,需要等待才好,这样明显不太符合我们的本意,所以就有了这个 preferWriter 当写锁 解开的时候 赋值为false。那么就是读锁优先。

    1. public class ReadWriteLock {
    2. private int readingReader = 0;//正在读的线程数
    3. private int writingWriter = 0;//正在写的线程数
    4. private int waitingWriter = 0;//正在等待写的线程数
    5. private boolean preferWriter = true;//如果写入优先 那么就是true
    6. public synchronized void readLock() throws InterruptedException {
    7. while (writingWriter > 0 || (preferWriter && waitingWriter > 0)) {
    8. wait();
    9. }
    10. readingReader++;
    11. }
    12. public synchronized void readUnlock() {
    13. readingReader--;
    14. preferWriter = true;
    15. notifyAll();
    16. }
    17. public synchronized void writeLock() throws InterruptedException {
    18. waitingWriter++;
    19. try {
    20. while (readingReader > 0 || writingWriter > 0) {
    21. wait();
    22. }
    23. } finally {
    24. waitingWriter--;
    25. }
    26. writingWriter++;
    27. }
    28. public synchronized void writeUnlock() {
    29. writingWriter--;
    30. preferWriter = false;
    31. notifyAll();
    32. }
    33. }
    1. public class ReadThread extends Thread {
    2. private final Data data;
    3. public ReadThread(Data data) {
    4. this.data = data;
    5. }
    6. @Override
    7. public void run() {
    8. super.run();
    9. try {
    10. while (true) {
    11. char[] readBuf = data.read();
    12. System.out.println(Thread.currentThread().getName() + "-reads-" + String.valueOf(readBuf));
    13. }
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. }
    1. public class WriteThread extends Thread{
    2. private final Data data;
    3. private Random random = new Random();
    4. private String filter;
    5. private int index = 0;
    6. public WriteThread(Data data,String filter) {
    7. this.data = data;
    8. this.filter = filter;
    9. }
    10. @Override
    11. public void run() {
    12. super.run();
    13. try {
    14. while (true){
    15. char c = nextChar();
    16. data.writee(c);
    17. Thread.sleep(random.nextInt(1000));
    18. }
    19. }catch (InterruptedException e){
    20. }
    21. }
    22. private char nextChar() {
    23. char c = filter.charAt(index);
    24. index++;
    25. if(index>=filter.length()){
    26. index = 0;
    27. }
    28. return c;
    29. }
    30. }
    1. public class Data {
    2. private final ReadWriteLock lock = new ReadWriteLock();
    3. private final char[] buffer;
    4. public Data(int size) {
    5. buffer = new char[size];
    6. for (int i = 0; i < buffer.length; i++) {
    7. buffer[i] = '*';
    8. }
    9. }
    10. public char[] read() throws InterruptedException {
    11. lock.readLock();
    12. try {
    13. return doRead();
    14. } finally {
    15. lock.readUnlock();
    16. }
    17. }
    18. public void writee(char c) throws InterruptedException {
    19. lock.writeLock();
    20. try {
    21. doWrite(c);
    22. }finally {
    23. lock.writeUnlock();
    24. }
    25. }
    26. private void doWrite(char c) {
    27. for (int i = 0; i < buffer.length; i++) {
    28. buffer[i] = c;
    29. slowly();
    30. }
    31. }
    32. private char[] doRead() {
    33. char[] newbuf = new char[buffer.length];
    34. for (int i = 0; i < buffer.length; i++) {
    35. newbuf[i] = buffer[i];
    36. }
    37. slowly();
    38. return newbuf;
    39. }
    40. private void slowly() {
    41. try {
    42. Thread.sleep(50);
    43. } catch (InterruptedException e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. }
    1. public class Main {
    2. public static void main(String[] args) {
    3. Data data = new Data(10);
    4. new ReadThread(data).start();
    5. new ReadThread(data).start();
    6. new ReadThread(data).start();
    7. new ReadThread(data).start();
    8. new ReadThread(data).start();
    9. new ReadThread(data).start();
    10. new WriteThread(data,"ABCDEF").start();
    11. new WriteThread(data,"abcdef").start();
    12. }
    13. }