Java读写锁分离设计模式


prtyaa
prtyaa 2023-12-30 21:26:59 51108 赞同 0 反对 0
分类: 资源
在多线程的环境下,对于共享资源的访问,为了防止资源出现不同步的情况出现,可以使用synchronized关键字对资源进行同步,使得同一时间只有一个线程能够访问共享资源。但synchronized是具有排他性质的锁,使用它会降低系统性能,而我们知道对于共享资源的操作,可以归为两类:读和写。而读操作并不会影响共享资源,而写操作才需要进行同步,对此可以设计出一种读写分离模式的锁,在同一时间可以要么只能读,要么只能写,而读线程可以有多个,写线程只能有一个。

定义锁的接口,解锁和加锁方法

public interface Lock {
    void lock() throws InterruptedException;
    void unlock();
}

定义读写锁的接口

public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
    int getWritingWriters();
    int getWaitingWriters();
    int getReadingReaders();

    //工厂方法,创建ReadWriteLock,下面是带构造参数传
    static ReadWriteLock readWriterLock(){
        return new ReadWriteLockImp();
    }
    static ReadWriteLock readWriterLock(boolean preferWriter){
        return new ReadWriteLockImp(preferWriter);
    }
}

3个get方法分别是:

  1. 获取正在写入中的线程数(只能为0和1)
  2. 获取等待写入的线程数
  3. 获取正在读取的线程数

读写锁实现:

public class ReadWriteLockImp implements ReadWriteLock {
    //定义对象锁
    private final Object MUTEX = new Object();
    //当前有多少个线程写入
    private int writingWriters = 0;
    //当前多少个线程正在等待写入
    private int waitingWriters = 0;
    //当前多少个线程正在读
    private int readingReaders = 0;
    //是否偏好于写
    private boolean preferWriter;

    //不填默认为true
    public ReadWriteLockImp() {
        this(true);
    }

    public ReadWriteLockImp(boolean preferWriter) {
        this.preferWriter = preferWriter;
    }

    @Override
    public Lock readLock() {
        return new ReadLock(this);
    }

    @Override
    public Lock writeLock() {
        return new WriteLock(this);
    }

    //正在写的线程增加1
    public void incrementWritingWriters() {
        this.writingWriters++;
    }

    //等待写的线程增加1
    public void incrementWaitingWriters() {
        this.waitingWriters++;
    }

    //正在读的线程增加1
    public void incrementReadingReaders() {
        this.readingReaders++;
    }

    //反之
    public void decrementWritingWriters() {
        this.writingWriters--;
    }

    public void decrementWaitingWriters() {
        this.waitingWriters--;
    }

    public void decrementReadingReaders() {
        this.readingReaders--;
    }

    @Override
    public int getWritingWriters() {
        return this.writingWriters;
    }

    @Override
    public int getWaitingWriters() {
        return this.waitingWriters;
    }

    @Override
    public int getReadingReaders() {
        return this.readingReaders;
    }

    //获取对象锁
    public Object getMUTEX() {
        return MUTEX;
    }

    //获取是否偏向写锁
    public boolean getPreferWriter() {
        return preferWriter;
    }

    //设置偏好锁
    public void setPreferWriter(boolean preferWriter) {
        this.preferWriter = preferWriter;
    }
}

读锁的实现:

public class ReadLock implements Lock {
    private final ReadWriteLockImp readWriteLockImp;

    public ReadLock(ReadWriteLockImp readWriteLockImp) {
        this.readWriteLockImp = readWriteLockImp;
    }

    @Override
    public void lock() throws InterruptedException {
        //使用对象锁
        synchronized (readWriteLockImp.getMUTEX()) {
            //如果现在有写操作,或者有写操作正在等待写入且偏好写,则只能挂起等待
            while (readWriteLockImp.getWritingWriters() > 0 ||
                    (readWriteLockImp.getPreferWriter()
                            && readWriteLockImp.getWaitingWriters() > 0)) {
                readWriteLockImp.getMUTEX().wait();
            }
            //获取锁成功
            readWriteLockImp.incrementReadingReaders();
        }
    }

    @Override
    public void unlock() {
        synchronized (readWriteLockImp.getMUTEX()) {
            //读线程数量减一
            readWriteLockImp.decrementReadingReaders();
            //将偏好设置为true,让写线程获取更多机会
            readWriteLockImp.setPreferWriter(true);
            //唤醒挂起中的writer线程
            readWriteLockImp.getMUTEX().notifyAll();
        }
    }
}

写锁的实现:

public class WriteLock implements Lock {
    private ReadWriteLockImp readWriteLockImp;

    public WriteLock(ReadWriteLockImp readWriteLockImp){
        this.readWriteLockImp = readWriteLockImp;
    }
    @Override
    public void lock() throws InterruptedException {
        synchronized (readWriteLockImp.getMUTEX()){
            //此时让等待写锁的线程数量+1
            try {
                readWriteLockImp.incrementWaitingWriters();
                //如果当前正有读线程在运行,或者有写线程运行,则挂起
                while (readWriteLockImp.getReadingReaders()>0
                        || readWriteLockImp.getWritingWriters()>0){
                    readWriteLockImp.getMUTEX().wait();
                }
            }finally {
                //获取了写锁,等待-1
                readWriteLockImp.decrementWaitingWriters();
            }
            //正在写入加1
            readWriteLockImp.incrementWritingWriters();
        }
    }

    @Override
    public void unlock() {
        synchronized (readWriteLockImp.getMUTEX()){
            //写入线程数量-1
            readWriteLockImp.decrementWritingWriters();
            //写偏好改为false,让读线程更多机会
            readWriteLockImp.setPreferWriter(false);
            readWriteLockImp.getMUTEX().notifyAll();
        }
    }
}

读写锁实现成功,来看一看具体使用

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

//读写锁的使用
public class ShareData {
    //定义共享数据源
    private final List<Character> container = new ArrayList<>();
    //构造ReadWriteLock
    private final ReadWriteLock readWriteLock = ReadWriteLock.readWriterLock();
    //创建读锁
    private final Lock readLock = readWriteLock.readLock();
    //创建写锁
    private final Lock writeLock = readWriteLock.writeLock();
    private final int length;

    public ShareData(int length) {
        this.length = length;
        IntStream.range(0, length).forEach(i -> {
            container.add(i, 'a');
        });
    }

    public char[] read() throws InterruptedException {
        try {
            //创建读锁
            readLock.lock();
            char[] newBuffer = new char[length];
            IntStream.range(0, length).forEach(i -> {
                newBuffer[i] = container.get(i);
            });
            slowly();
            return newBuffer;
        } finally {
            //解锁
            readLock.unlock();
        }
    }

    public void write(char a) throws InterruptedException {
        try {
            writeLock.lock();
            IntStream.range(0, length).forEach(i -> {
                container.add(i, a);
            });
            slowly();
        } finally {
            writeLock.unlock();
        }
    }

    //模拟读取时间
    private void slowly() {

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
prtyaaL2
粉丝 1 资源 1949 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  125
统信桌面专业版【全盘安装UOS系统】介绍  120
银河麒麟桌面操作系统安装佳能打印机驱动方法  112
银河麒麟桌面操作系统 V10-SP1用户密码修改  105
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益209.03元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!