读写锁分离设计
为什么需要分离?
在多线程下读取数据不能串行化,否则会导致效率下降。这里必须使用读写锁分离如下表所示
- 在读的情况时另外线程读操作,不需要同步
- 在读的情况,另外线程在写操作,必须同步加锁
- 一个线程在写入,另一个线程在读取需要同步加锁
- 一个线程在写入,另个线程在写需要同步加锁
定义四个变量
readingReader :正在读的取得reder线程数量
waitingReader :正在等待的reader线程数量
writingWriter :正在写入的writer线程数量
waitingWriter :正在等待的writer数量
public class ReadWriteDemo {
private int readingReader = 0;
private int waitingReader = 0;
private int writingWriter = 0;
private int waitingWriter = 0;
//读读并行
//读写串行
//写写串行化
//写读串行
//读取加锁
public synchronized void readLock() throws InterruptedException {
waitingReader++;
try {
while(writingWriter > 0){
this.wait();
}
readingReader++;
}finally {
this.waitingReader--;
}
}
//读取解锁
public synchronized void readUnlock(){
this.readingReader--;
this.notifyAll();
}
//写入加锁
public synchronized void writeLock() throws InterruptedException {
this.waitingWriter ++;
try {
while(readingReader > 0 || writingWriter > 0){
this.wait();
}
writingWriter ++;
}finally {
this.waitingWriter--;
}
}
//写入解锁
public synchronized void writeUnlock(){
this.writingWriter--;
this.notifyAll();
}
}
优化
此时想要写入的线程优先级更高,需要加上–boolean的preferWriter变量
1.加入构造
public ReadWriteLock() {
this(true);
}
public ReadWriteLock(boolean preferWriter) {
this.preferWriter = preferWriter;
}
2.在读锁拿锁条件加入是不是writer的优先级更高,是不是还有人在等着写,如果是的话那就不能拿读锁,只能让写来拿去锁
//读锁
public synchronized void readLock() throws InterruptedException {
waitingReaders++;
//判断有没有人写
try {
while (writingWriter > 0 || (preferWriter && waitingWriters > 0)) {
this.wait();
}
readingReaders++;
} finally {
waitingReaders--;
}
}
编写测试
1.创建共享数据shareData
public class SharedData {
private final ReadWriteLock LOCK = new ReadWriteLock();
private char[] data;
private int size;
public SharedData(int size) {
this.data = new char[size];
this.size = size;
Arrays.fill(data, '*');
}
public void read(){
try {
LOCK.readLock();
char[] chars = doRead();
System.out.println(Thread.currentThread().getName()+" read ==== "+String.valueOf(chars));
}catch (InterruptedException e){
e.printStackTrace();
}finally {
LOCK.readUnlock();
}
}
private char[] doRead(){
char[] newData = new char[size];
for (int i =0;i<size;i++){
newData[i] = data[i];
}
return newData;
}
public void write(char c){
try {
LOCK.writeLock();
Arrays.fill(data,c);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
LOCK.writeUnlock();
}
}
}
2.创建reader线程类
public class ReadWorker extends Thread {
private final SharedData sharedData;
public ReadWorker(SharedData data){
this.sharedData = data;
}
@Override
public void run() {
try {
while(true){
sharedData.read();
Thread.sleep(200L);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.创建writer线程类
public class WriteWorker extends Thread{
private final SharedData sharedData;
private final String filter;
private int index = 0;
public WriteWorker(SharedData sharedData,String filter){
this.sharedData = sharedData;
this.filter = filter;
}
@Override
public void run() {
try {
while(true){
sharedData.write(nextChar());
Thread.sleep(200L);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private char nextChar(){
if(index >= filter.length())
index = 0;
return filter.charAt(index++);
}
}
4.创建客户端测试
public class MainApplication {
public static void main(String[] args) {
SharedData sharedData = new SharedData(10);
new ReadWorker(sharedData).start();
new ReadWorker(sharedData).start();
new ReadWorker(sharedData).start();
new ReadWorker(sharedData).start();
new WriteWorker(sharedData,"qwertys").start();
new WriteWorker(sharedData,"asdfghjk").start();
new WriteWorker(sharedData,"zxcvbnm").start();
}
}
5.结果