我是靠谱客的博主 聪慧花卷,最近开发中收集的这篇文章主要介绍【详解】Java并发之读写锁分离设计模式分析编码验证,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

分析

读写锁最重要的需求是:多个线程如果都是在读取数据,如果依然采用加锁的方式,会严重影响效率。所以需要对读写锁进行分离

这种方式适用于:读取的操作比较多

需要考虑以下冲突,否则会出现数据不一致的情况

冲突策略
读 — 读并行化
读 — 写串行化
写 — 写串行化

读写锁的设计思想就是避免冲突

编码

首先设计的读写锁

  • 在获取读锁的时候,需要看看是否存在正在写的线程
  • 在获取写锁的时候,需要看看是否存在正在写的线程或者正在读的线程
  • 释放锁的就是在完成后,唤醒正在等待的全部线程
public class ReadWriteLock {

    private int readingReaders = 0;//当前有几个线程正在读
    private int waitingReaders = 0;//有几个线程想读,但是读取不了
    private int writeingWriters = 0;//正在写的线程数,最多一个
    private int waitingWriters = 0;//等待写的线程数

    /**
     * 读锁只需要关心是否有没有人在写
     */

    public synchronized void readLock() {
        this.waitingReaders++;

        try {
            //如果此时有线程正在写,则不允许读的操作,陷入阻塞
            while (writeingWriters > 0) {
                this.wait();
            }
            //此时没有线程正在写
            this.readingReaders++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            waitingReaders--;
        }
    }

    /**
     * 释放读的锁
     */
    public synchronized void readUnlock() {
        this.readingReaders--;
        this.notifyAll();
    }


    /**
     * 写锁
     */
    public synchronized void writeLock() {
        this.waitingWriters++;

        try {
            //判断是否有线程正在读或者写
            while (readingReaders>0 || writeingWriters>0){
                this.wait();
            }
            writeingWriters++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            this.waitingWriters--;
        }
    }

    /**
     * 释放写锁
     */
    public synchronized void wirteUnlock(){
        this.writeingWriters--;
        this.notifyAll();
    }

}

验证

设计两个类分别去读取数据和写入数据,然后创建客户端,创建多个写线程和读线程

共享的数据

/**
 * 共享的数据
 */
public class ShareData {
    private final char [] buffer;

    private final ReadWriteLock lock = new ReadWriteLock();

    public ShareData(int size) {
        this.buffer = new char[size];
        for (int i = 0; i < size; i++) {
            buffer[i] = '*';
        }
    }


    /**
     * 写的操作
     * @param c 写的字符
     */
    public void write(char c){
        try {
            lock.writeLock();
            doWrite(c);
        } finally {
            lock.wirteUnlock();
        }

    }

    private void doWrite(char c) {
        for (int i = 0; i < buffer.length; i++) {
            buffer[i] = c;
        }
        slowly(10);
    }

    public char[] read(){
        try {
            lock.readLock();
            return doRead();
        } finally {
            lock.readUnlock();
        }
    }

    /**
     * 读的操作,返回一个数据的副本
     * @return
     */
    private char[] doRead() {
        char [] newBuf = new char[buffer.length];
        for (int i = 0; i < buffer.length; i++) {
            newBuf[i] = buffer[i];
        }
        slowly(50);
        return newBuf;
    }

    /**
     * 休眠
     * @param time 休眠时间
     */
    private void slowly(int time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

写的线程

public class WriteWorker extends Thread {
    private  final Random random = new Random(System.currentTimeMillis());

    private final ShareData data;
    private final String filer;

    private int index = 0;


    public WriteWorker(ShareData data, String filer) {
        this.data = data;
        this.filer = filer;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                char c = nextChar();
                data.write(c);
                Thread.sleep(random.nextInt(1000));
            }
        } catch (InterruptedException e) {
        }

    }

    /**
     * 获取一个字符,写到数据
     *
     * @return
     */
    private char nextChar() {
        char c = filer.charAt(index);
        index++;
        if (index >= filer.length()) {
            index = 0;
        }
        return c;
    }
}

读取的线程

public class ReadWorker extends Thread {
    private final Random random = new Random();
    private final ShareData data;


    public ReadWorker(ShareData data) {
        this.data = data;
    }

    @Override
    public void run() {

        try {
            while (!Thread.interrupted()){
                char[] read = data.read();
                System.out.println(Thread.currentThread().getName() + " reads " + String.valueOf(read));
                Thread.sleep(random.nextInt(1000));
            }
        } catch (InterruptedException e) {

        }

    }
}

客户端

public class Client {
    public static void main(String[] args) throws InterruptedException {
        ShareData data = new ShareData(5);
        new ReadWorker(data).start();
        new ReadWorker(data).start();
        new ReadWorker(data).start();
        new ReadWorker(data).start();
        new ReadWorker(data).start();

        new WriteWorker(data,"uiiakihlkbjhao465117").start();
        new WriteWorker(data,"uiiakihlkbjhao465117").start();

        Thread.sleep(10_000);
        ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
        threadGroup.interrupt();
    }
}

结果:

Thread-1 reads *****
Thread-2 reads *****
Thread-0 reads *****
Thread-3 reads *****
Thread-4 reads *****
Thread-3 reads uuuuu
Thread-4 reads uuuuu
Thread-3 reads uuuuu
Thread-0 reads uuuuu
Thread-3 reads uuuuu
Thread-2 reads iiiii
Thread-1 reads iiiii
Thread-3 reads kkkkk
Thread-1 reads kkkkk
Thread-4 reads kkkkk

最后

以上就是聪慧花卷为你收集整理的【详解】Java并发之读写锁分离设计模式分析编码验证的全部内容,希望文章能够帮你解决【详解】Java并发之读写锁分离设计模式分析编码验证所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部