[TOC]
转载地址: https://blog.csdn.net/weixin_39715061/article/details/81081008
需求简明分析
- 读的时候有好几个线程一起去读它 并行的去读,不会对下一个产生问题。
- 如果有人在写 你就不能读了 线程就会wait住 ,如果有人在读,就不能写,暂停住。
- 也就是最终保证它能读的时候不写,写的时候不读,同时写的时候只能有一个线程在写:
ReadWriteLock
注意:这个读方法readLock,加入了synchronize关键字,但是他没有直接去读取数据, 只是为了判断在读的时候, 有没有线程对公共数据进行写的操作, 如果没有的话, 后面方法的读都是并发操作的,如果有的话,读就要wait模式了。
public class ReadWriteLock {
// 定义变量
private int readingReaders = 0;// 当前有几个线程进行读的操作
private int waitingReaders = 0;// 有几个线程想读却读不了 方法放进waitset队列
private int writingWriters = 0;// 当前有几个线程让它写
private int waitingWriters = 0;// 在等着释放锁去写
// 为了避免一直读 那么给它一个默认更喜欢
private boolean preferWriter = true;
public ReadWriteLock() {
this(true);
}
public ReadWriteLock(boolean preferWriter) {
this.preferWriter = preferWriter;
}
// 让它去读,
public synchronized void readLock() throws InterruptedException {
this.waitingReaders++;
try {
// 如果当前有线程在写 同时写的数多
while (writingWriters > 0 || (preferWriter && waitingWriters > 0)) {
// 你就不能读了
System.out.println("有其他线程正在进行写或者等待写的操作,为保证数据的一致性,请稍后在读");
this.wait();
}
// 如果它不写了,你就去读,代表当前有一个线程在读
this.readingReaders++;
} finally {
// 等待读不等了,不在waitset里面了等待读的就少了一个
this.waitingReaders--;
}
}
// 放弃读的锁
public synchronized void readUnlock() {
this.readingReaders--; // 释放了一个read的锁
this.notifyAll();
}
// 写的操作
public synchronized void writeLock() throws InterruptedException {
this.waitingWriters++;
try {
// 当有读的或者在写的
while (readingReaders > 0 || writingWriters > 0) {
// 就不能写了
System.out.println("有其他线程正在进行读或者进行写的操作,为保证数据的一致性,请稍后在写");
this.wait();
}
// 等带写的jia+ 有人在写
this.writingWriters++;
} finally {
// 如果从阻塞状态退出
this.waitingWriters--;
}
}
public synchronized void writeUnlock() {
this.writingWriters--;
// 通知你其他可以去操作了
this.notifyAll();
}
}
SharedData 公共资源
public class SharedData {
// 共享的数据读的操作不断从里面读,
// 写的数据往里面填数据
private char[] buffer;
// 定义一个随机值,要去随机休眠的
private final ReadWriteLock lock = new ReadWriteLock();
public SharedData(int size) {
// 初始化值
this.buffer = new char[size];
for (int i = 0; i < size; i++) {
this.buffer[i] = '*';
}
}
// 提供一个read方法 返回char[] 数据
public char[] read() throws InterruptedException {
try {// 获取read这个锁
lock.readLock();
// 读的方法
return this.doRead();
} finally {
// 确保释放掉
lock.readUnlock();
}
}
// 写的操作
public void write(char[] charData) throws InterruptedException {
try {
// 拿锁因为访问的资源是同一个
lock.writeLock();
// 去写东西
this.doWrite(charData);
} finally {
// 释放掉这个锁
lock.writeUnlock();
}
}
private void doWrite(char[] charData) {
this.buffer = charData;
}
private char[] doRead() {
// 创建一个 副本 吧里面的数据读到newBuf里面
char[] newBuf = new char[buffer.length];
// 赋值
for (int i = 0; i < buffer.length; i++)
newBuf[i] = buffer[i];
slowly(1_000);// 休眠一下 模拟读
return newBuf;
}
private void slowly(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
}
}
}
ReaderWorker
public class ReaderWorker extends Thread {
// 共享的数据
private final SharedData data;
public ReaderWorker(SharedData data) {
this.data = data;
}
@Override
public void run() {
try {
while (true) {
char[] readBuf = data.read();
System.out.println(Thread.currentThread().getName() + " reads " + String.valueOf(readBuf));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ReadWriteLock
public class ReadWriteLock {
// 定义变量
private int readingReaders = 0;// 当前有几个线程进行读的操作
private int waitingReaders = 0;// 有几个线程想读却读不了 方法放进waitset队列
private int writingWriters = 0;// 当前有几个线程让它写
private int waitingWriters = 0;// 在等着释放锁去写
// 为了避免一直读 那么给它一个默认更喜欢
private boolean preferWriter = true;
public ReadWriteLock() {
this(true);
}
public ReadWriteLock(boolean preferWriter) {
this.preferWriter = preferWriter;
}
// 让它去读,
// 注意这个读的锁并没有直接去读取数据, 只是为了判断在读的时候, 有没有线程对公共数据进行写的操作, 如果没有的话, 后面方法的读都是并发操作的。
public synchronized void readLock() throws InterruptedException {
this.waitingReaders++;
try {
// 如果当前有线程在写 同时写的数多
while (writingWriters > 0 || (preferWriter && waitingWriters > 0)) {
// 你就不能读了
System.out.println("有其他线程正在进行写或者等待写的操作,为保证数据的一致性,请稍后在读");
this.wait();
}
// 如果它不写了,你就去读,代表当前有一个线程在读
this.readingReaders++;
} finally {
// 等待读不等了,不在waitset里面了等待读的就少了一个
this.waitingReaders--;
}
}
// 放弃读的锁
public synchronized void readUnlock() {
this.readingReaders--; // 释放了一个read的锁
this.notifyAll();
}
// 写的操作
public synchronized void writeLock() throws InterruptedException {
this.waitingWriters++;
try {
// 当有读的或者在写的
while (readingReaders > 0 || writingWriters > 0) {
// 就不能写了
System.out.println("有其他线程正在进行读或者进行写的操作,为保证数据的一致性,请稍后在写");
this.wait();
}
// 等带写的jia+ 有人在写
this.writingWriters++;
} finally {
// 如果从阻塞状态退出
this.waitingWriters--;
}
}
public synchronized void writeUnlock() {
this.writingWriters--;
// 通知你其他可以去操作了
this.notifyAll();
}
}
ReadWritLockClient
public class ReadWritLockClient {
public static void main(String[] args) {
final SharedData sharedData = new SharedData(10);
new ReaderWorker(sharedData).start();
new ReaderWorker(sharedData).start();
new ReaderWorker(sharedData).start();
new ReaderWorker(sharedData).start();
new ReaderWorker(sharedData).start();
// new WriterWorker(sharedData, "qwertyuiopasdfg").start();
new WriterWorker(sharedData, "maizi").start();
}
}
运行结果
有其他线程正在进行读或者进行写的操作,为保证数据的一致性,请稍后在写
Thread-0 reads **********
有其他线程正在进行读或者进行写的操作,为保证数据的一致性,请稍后在写
Thread-2 reads **********
Thread-3 reads **********
Thread-1 reads **********
有其他线程正在进行写或者等待写的操作,为保证数据的一致性,请稍后在读
Thread-4 reads **********
有其他线程正在进行写或者等待写的操作,为保证数据的一致性,请稍后在读
有其他线程正在进行写或者等待写的操作,为保证数据的一致性,请稍后在读
有其他线程正在进行写或者等待写的操作,为保证数据的一致性,请稍后在读
有其他线程正在进行写或者等待写的操作,为保证数据的一致性,请稍后在读
I am write worker ......... Thread[Thread-5,5,main][C@39005f74
数据写入完毕
Thread-1 reads maizi
Thread-3 reads maizi
如上可以看到, 一开始有5条线程进行读的操作, 提示, 有人在读,写的操作需要wait, 而后读取完成后, 开始一条写的线程进入,开始写,这个时候5条线程需要等待写的操作完成,然后在可以开始读。 写完成后, 所有的就进行读取操作了。
需要注意里面的finally里面有很多的notifyAll的操作,这些都是为了防止线程中断时候,防止死锁处理的。 notityAll的唤醒主要是锁住同一个类的的时候, 线程和线程之间的通信的处理。
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付