一、简介
1.读写锁:在同一时刻允许多个读线程访问,但是当写线程访问,所有的写线程和读线程均被阻塞。读写锁维护了一个读锁加一个写锁,通过读写锁分离的模式来保证线程安全,性能高于一般的排他锁。
2.读写锁分离设计模式有两种名称:
①.ReadWritLock Design Pattern
②Reader-Writer Design Pattern
3.Reader-Writeer Design Pattern是一种将对于共享资源的访问与修改操作分离,称为读写分离。即访问是reader,修改是write,用单独的线程来处理。可以允许多个reader,但是不允许同时多个写入或者在读的过程中有写入。
由于对于实例状态的读取,并不会破坏状态的完整性且状态也不会修改,可以允许多个线程同时访问操作。但是若在写入的过程中,会更改实例的状态,此时就需要对于写入做保护,防止其他线程来进行读操作和写操作。
在多个线程共享一个实例的时候,会有参考实例状态的线程即仅仅读取实例状态的Reader参与者,并且也会有改变实例的状态的线程即Writer参与者,此时就需要运用这种模式。
这种模式在读取不会冲突下,允许多个Reader参与者同时reader,提高了性能。不用单纯的在每次读的时候利用Synchronized来使得只能允许一个线程读操作,而是利用了外部定义的逻辑锁来设置允许多个Reader同时操作。在读取的操作比写入的操作多的时候,也可以使用这个模式
二、遵循原则
1.read read 并行化
2.read write 不允许
3.write write 不允许
三、代码实现
①.ReaderWriterLock类,也是读写锁分离的核心类
package chapter2.readerwriter;
/**
* @author czd
* 读写锁分离核心类
*/
public class ReaderWriterLock {
/**
* waitingReaders:正在等待读操作的线程的数量
* readingReaders:正在进行读操作的线程的数量
* waitingWriters:正在等待写操作的线程的数量
* writingWriters:正在进行写操作的线程的数量
*/
private int waitingReaders = 0;
private int readingReaders = 0;
private int waitingWriters = 0;
private int writingWriters = 0;
/**
* 获取读操作的锁
*/
public synchronized void readLock(){
waitingReaders++;
try {
//如果有线程在进行写操作
if (writingWriters > 0){
this.wait();
}
//等待完,即拿到锁的权限,就进行读操作
readingReaders++;
}catch (Exception e){
e.printStackTrace();
}finally {
waitingReaders--;
}
}
/**
* 放弃读操作的锁
*/
public synchronized void readUnLock(){
readingReaders--;
notifyAll();
}
/**
* 获取写操作的锁
*/
public synchronized void writerLock(){
waitingWriters++;
try {
if (readingReaders > 0 || writingWriters > 0){
this.wait();
}
//睡眠完,即拿到锁的权限,就进行写操作
writingWriters++;
}catch (Exception e){
e.printStackTrace();
}finally {
waitingWriters--;
}
}
/**
* 放弃写操作的锁
*/
public synchronized void writerUnLock(){
writingWriters--;
notifyAll();
}
}
②.SharedData,共享数据类
package chapter2.readerwriter;
/**
* @author czd
* 共享数据的类,模拟数据
*/
public class SharedData {
private char[] data;
private ReaderWriterLock lock = new ReaderWriterLock();
/**
* 初始化数据,都为 '*'
* @param size
*/
public SharedData(int size){
data = new char[size];
for (int i = 0; i < size; i++){
data[i] = '*';
}
}
/**
* 读取数据的方法
* @return
*/
public char[] read(){
try {
lock.readLock();
return doRead();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.readUnLock();
}
return data;
}
private char[] doRead(){
char [] newData = new char[data.length];
for (int i = 0; i < data.length; i++){
newData[i] = data[i];
}
try {
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
return newData;
}
/**
* 写数据的方法
* @param c
*/
public void write(char c){
try {
lock.writerLock();
doWrite(c);
}catch (Exception e){
e.printStackTrace();
}finally {
lock.writerUnLock();
}
}
private void doWrite(char c){
for (int i = 0; i < data.length; i++){
data[i] = c;
try {
Thread.sleep(10);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
③.ReadWorker,进行读操作的工作类
package chapter2.readerwriter;
/**
* @author czd
* 进行读操作的工作类
*/
public class ReadWorker extends Thread {
private SharedData sharedData ;
public ReadWorker(SharedData sharedData){
this.sharedData = sharedData;
}
@Override
public void run() {
try {
while(true){
//进行读操作
char [] chars = sharedData.read();
System.out.println(Thread.currentThread().getName() + " read " + String.valueOf(chars) );
}
} catch (Exception e){
e.printStackTrace();
}
}
}
④.WriterWorker,进行写操作的工作类
package chapter2.readerwriter;
/**
* @author czd
* 进行写操作的工作类
*/
public class WriterWorker extends Thread {
/**
* filler:模拟数据,可以是字符串,字符等虚拟数据
*/
private SharedData sharedData ;
private String filler;
private int index = 0;
public WriterWorker(SharedData sharedData , String filler){
this.sharedData = sharedData;
this.filler = filler;
}
public char nextChar(){
char c = filler.charAt(index);
index++;
if(index >= filler.length()){
index = 0;
}
return c;
}
@Override
public void run() {
try {
while (true){
//进行写操作
char c =nextChar();
sharedData.write(c);
Thread.sleep(100);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
⑤.ReaderWriterClient
package chapter2.readerwriter;
/**
* @author czd
* 运行读写锁分离的类,看结果
*/
public class ReaderWriterClient {
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 ReadWorker(sharedData).start();
new WriterWorker(sharedData , "qwertyuiop").start();
new WriterWorker(sharedData , "QWERTYUIOP").start();
}
}
四、查看运行结果