Read-Write Lock Pattern【读写】
一:Read-Write Lock Pattern的参与者
--->读写锁
--->数据(共享资源)
--->读线程
--->写线程
二Read-Write Lock Pattern模式什么时候使用
--->
* 为了多线线程环境下保护数据安全,我们必须避免的冲突
* 一个线程读取,另一个线程写入的read-write conflick
* 一个线程写入,另一个线程写入的write-write conflick
* 一个线程读取,另一个线程也在读取不会产生冲突
*
* 当线程想要获取读取锁定时:
* -->已经有线程在执行写入,则等待。不等待,则发生read-write conflick
* -->已经有线程在读取,则不需要等待。不存在read-read conflick
*
* 当线程想要获取写入锁定时:
* -->已经有线程在执行写入,则等待。不等待,则发生write-write conflick
* -->已经有线程在执行读取,则等待。不等待,则发生read-write conflick
--->利用同时(读取)不会引起数据冲突的特性,提高系统的性能
--->适合读取操作繁重时
--->适合读取操作比写入操作繁重时
三:Read-Write Lock Pattern思考
--->
四进阶说明
--->
读写锁
1 package com.yeepay.sxf.thread6; 2 /** 3 * 读写锁 4 * @author sxf 5 * 6 * 为了多线线程环境下保护数据安全,我们必须避免的冲突 7 * 一个线程读取,另一个线程写入的read-write conflick 8 * 一个线程写入,另一个线程写入的write-write conflick 9 * 一个线程读取,另一个线程也在读取不会产生冲突 10 * 11 * 当线程想要获取读取锁定时: 12 * -->已经有线程在执行写入,则等待。不等待,则发生read-write conflick 13 * -->已经有线程在读取,则不需要等待。不存在read-read conflick 14 * 15 * 当线程想要获取写入锁定时: 16 * -->已经有线程在执行写入,则等待。不等待,则发生write-write conflick 17 * -->已经有线程在执行读取,则等待。不等待,则发生read-write conflick 18 * 19 */ 20 public class ReadWriteLock { 21 //正在读取的线程个数 22 private Integer readInteger=0; 23 //正在写入的线程个数(最大值为1) 24 private Integer writeInteger=0; 25 //正在等待获取写入锁定的线程个数 26 private Integer writeWaitInteger=0; 27 //获取写入锁定优先的话,为true 28 private boolean writeBoolean=false; 29 30 //获取读取锁的方法 31 public synchronized void readLock() throws InterruptedException{ 32 //如果有写入操作 ||写入优先并且存在等待写入的线程 则 读取线程等待 33 while(writeInteger>0||(writeBoolean&&writeWaitInteger>0)){ 34 wait(); 35 } 36 //读取线程加1 37 readInteger++; 38 } 39 //释放读取锁定的方法 40 public synchronized void readUnLock(){ 41 //读取减一 42 readInteger--; 43 //将写入设置优先 44 writeBoolean=true; 45 //唤醒所有线程 46 notifyAll(); 47 } 48 49 //获取写入锁定 50 public synchronized void writeLock() throws InterruptedException{ 51 //等待写入线程数量+1 52 writeWaitInteger++; 53 try { 54 //如果有读取线程或写入线程,则等待 55 while (readInteger>0||writeInteger>0) { 56 wait(); 57 } 58 }finally{ 59 //执行到这,等待线程-1 60 writeWaitInteger--; 61 } 62 //写入线程数+1 63 writeInteger++; 64 } 65 66 67 //释放写入锁定 68 public synchronized void writeUnLock(){ 69 //写入线程数-1 70 writeInteger--; 71 //写入的优先级去掉 72 writeBoolean=false; 73 //唤醒其他线程 74 notifyAll(); 75 } 76 77 }
数据类(公共资源)
1 package com.yeepay.sxf.thread6; 2 /** 3 * 数据类 4 * 持有公共数据+该公共数据的读写锁 5 * @author sxf 6 * 7 */ 8 public class Data { 9 //数据类持有的锁 10 private final ReadWriteLock lock=new ReadWriteLock(); 11 //要访问的公共数据 12 private final String[] buffer; 13 //构造器 14 public Data(int i){ 15 buffer=new String[i]; 16 for(int a=0;a<buffer.length;a++){ 17 buffer[a]="**"; 18 } 19 } 20 //读取数据的方法 21 public String[] read() throws InterruptedException{ 22 //获取读取锁定 23 lock.readLock(); 24 try { 25 //模拟读用了1秒 26 Thread.sleep(1000); 27 return doRead(); 28 } finally{ 29 //释放读取锁定 30 lock.readUnLock(); 31 } 32 33 } 34 //真正的读取操作 35 private String[] doRead(){ 36 return buffer; 37 } 38 39 //写入的操作 40 public void write(String a) throws InterruptedException{ 41 //获取写入锁定 42 lock.writeLock(); 43 try { 44 //模拟写用了3秒 45 Thread.sleep(1000); 46 doWrite(a); 47 }finally{ 48 //释放写入锁定 49 lock.writeUnLock(); 50 } 51 52 } 53 54 //真正的写操作 55 private void doWrite(String a){ 56 for(int i=0;i<buffer.length;i++){ 57 buffer[i]=a; 58 } 59 } 60 61 }
读线程
1 package com.yeepay.sxf.thread6; 2 3 /** 4 * 读线程 5 * @author sxf 6 * 7 */ 8 public class ReadThread implements Runnable{ 9 10 private Data data; 11 12 //构造器 13 public ReadThread(Data data) { 14 15 this.data=data; 16 } 17 @Override 18 public void run() { 19 while (true) { 20 try { 21 String [] aStrings=data.read(); 22 System.out.println("["+Thread.currentThread().getName()+"] 读取数据为:"+aStrings[0]); 23 } catch (InterruptedException e) { 24 // TODO Auto-generated catch block 25 e.printStackTrace(); 26 } 27 } 28 29 } 30 31 32 }
写线程
1 package com.yeepay.sxf.thread6; 2 /** 3 * 写线程 4 * * @author sxf 5 * 6 */ 7 public class WriteThead implements Runnable { 8 //数据 9 private Data data; 10 11 //构造器 12 public WriteThead(Data data) { 13 this.data=data; 14 } 15 16 @Override 17 public void run() { 18 19 while(true){ 20 for(int a=0;a<100;a++){ 21 String name=Thread.currentThread().getName(); 22 System.out.println("【"+name+"】写入"+a+"*"+name.substring(name.length()-2)); 23 try { 24 data.write(a+"*"+name.substring(name.length()-2)); 25 } catch (InterruptedException e) { 26 // TODO Auto-generated catch block 27 e.printStackTrace(); 28 } 29 } 30 } 31 } 32 33 34 }
测试类
1 package com.yeepay.sxf.thread6; 2 /** 3 * 测试类 4 * @author sxf 5 * 6 */ 7 public class Test { 8 9 public static void main(String[] args) { 10 //声明公共数据类 11 Data data=new Data(2); 12 //声明读取线程 13 Thread readThread1=new Thread(new ReadThread(data)); 14 readThread1.setName("读取线程sxf"); 15 Thread readThread2=new Thread(new ReadThread(data)); 16 readThread2.setName("读取线程sxs"); 17 Thread readThread3=new Thread(new ReadThread(data)); 18 readThread3.setName("读取线程sxy"); 19 20 //声明写入线程 21 Thread writeThread1=new Thread(new WriteThead(data)); 22 writeThread1.setName("写入线程yk"); 23 Thread writeThread2=new Thread(new WriteThead(data)); 24 writeThread2.setName("写入线程shl"); 25 Thread writeThread3=new Thread(new WriteThead(data)); 26 writeThread3.setName("写入线程shj"); 27 28 //开启线程 29 readThread1.start(); 30 readThread2.start(); 31 readThread3.start(); 32 33 writeThread1.start(); 34 writeThread2.start(); 35 writeThread3.start(); 36 37 38 } 39 }
打印结果
【写入线程yk】写入0*yk
【写入线程shj】写入0*hj
【写入线程shl】写入0*hl
[读取线程sxf] 读取数据为:**
[读取线程sxy] 读取数据为:**
[读取线程sxs] 读取数据为:**
【写入线程shj】写入1*hj
[读取线程sxs] 读取数据为:0*hj
[读取线程sxy] 读取数据为:0*hj
[读取线程sxf] 读取数据为:0*hj
【写入线程shj】写入2*hj
[读取线程sxf] 读取数据为:1*hj
[读取线程sxy] 读取数据为:1*hj
[读取线程sxs] 读取数据为:1*hj
【写入线程shl】写入1*hl
【写入线程shj】写入3*hj
【写入线程shl】写入2*hl
【写入线程shj】写入4*hj
【写入线程shl】写入3*hl
【写入线程shj】写入5*hj
【写入线程shl】写入4*hl