Java多线程设计模式-学习笔记-Read/Write Lock模式.

1. 模式描述:

大家想看就看把, 但是看的时候不能写哦.

Read-Write Lock Pattern将读取与写入分开处理. 在读取数据之前,必须获取用来读取的锁定.

而要写入的时候,则必须获取用来写入的锁定.

因为读取的时候,实例的状态不会改变,所以,就算有多个线程在同时读取也没有关系.但,有人在读

取的时候,不可做写入的操作.

写入的时候,实例的状态就会改变,于是,当有一个线程在写入的时候,其他的线程不可以进行读取或

写入.

一般来说,进行共享互斥会使程序性能变差,但将写入的共享互斥与读取的共享互斥分开思考,就可

以提升程序的性能.


2. 参与者:

2.1. Reader(读取者)参与者.

2.2. Writer(写入者)参与者.

2.3. SharedResource(共享资源)参与者.

2.4. ReadWriteLock(读写用锁定)参与者.

3. 示例程序:
3.1 ShareResource类 - SharedResource(共享资源)参与者:
package  com.quf.study.thread.readwritelock;

import  java.io.Serializable;

/**
 * <strong>Title : ShareResource<br></strong>
 * <strong>Description : </strong>共享数据实体类.<br> 
 * <strong>Create on : 2008-4-30<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public   final   class  ShareResource  implements  Serializable  {

    
/**
     * <code>serialVersionUID</code>-注释
     
*/

    
private static final long serialVersionUID = 235799050473308166L;
    
    
/**
     * <code>m_buf</code>-数据.
     
*/

    
private final char[] m_buf;
    
    
/**
     * <code>m_lock</code>-读写锁.
     
*/

    
private final ReadWriteLock m_lock = new ReadWriteLock(true);
    
    
/**
     * 构造函数
     
*/

    
public ShareResource(int size) {
        
// TODO Auto-generated constructor stub
        this.m_buf = new char[size];
        
for ( int i = 0 ; i < this.m_buf.length ;i++ ) {
            
this.m_buf[i] = '*';
        }

    }

    
    
/**
     * 读取数据.
     * <br>
     * 该方法中使用了before/after模式
     * <pre>
     *    before操作;
     *    
     *    try{
     *    
     *       execute();
     *       
     *    }finally{
     *    
     *       after操作;
     *       
     *    }
     * </pre>
     * 
@return 数据数组.
     
*/

    
public char[] read() throws InterruptedException{
        
        
//申请读取锁定.
        this.m_lock.readLock();
        
        
try {
            
return this.doRead();
            
        }
 finally {
            
            
this.m_lock.readUnLock();
        }


    }

    
    
/**
     * 写入数据.
     * 
@param data - 要写入的数据.
     
*/

    
public void write(char data) throws InterruptedException{
        
        
//申请写入锁定.
        
//this.m_lock.writeLock();
        
        
try {
            
this.m_lock.writeLock();
            
this.doWrite(data);
        }
 finally {
            
this.m_lock.writeUnLock();
        }

    }

    
    
/**
     * 读取数据.
     * 
@return 数据集合.
     
*/

    
private char[] doRead(){
        
        
char[] t_newBuf = new char[this.m_buf.length];
        
        
for ( int i = 0 ; i < this.m_buf.length ; i++ ) {
            t_newBuf[i] 
= this.m_buf[i];
        }

        
        
this.doSlowly();
        
        
return t_newBuf;
    }

    
    
/**
     * 写入数据.
     * 
@param data - 写入的数据.
     
*/

    
private void doWrite(char data){
        
        
for ( int i = 0 ; i < this.m_buf.length ;i++ ) {
            
this.m_buf[i] = data;
            
this.doSlowly();
        }

    }

    
    
/**
     * 线程休眠.
     
*/

    
private void doSlowly(){
        
try {
            
            Thread.sleep(
50);
            
        }
 catch (InterruptedException e) {
            
// TODO: handle exception
        }

    }


}
// END CLASS OF Data.

3.2 ReadWriteLock类 - 读写锁:
package  com.quf.study.thread.readwritelock;

import  java.io.Serializable;

/**
 * <strong>Title : ReadWriteLock<br></strong>
 * <strong>Description : </strong>读写锁类.<br>
 * <pre>
 * 为了保护安全性,必须防止以下两种冲突:
 * 1. 读取和写入冲突.
 * 2. 写入和写入冲突.
 * 
 * 为了达到以上的保护,可以获取读取锁定,写入锁定的条件有以下4种情况:
 * 1. 当线程想获取访问的锁定时........
 *    <1>已经有线程正在写入时,等待.
 *       理由: 不等待的话,会引起read-write conflict.
 *    <2>已经有线程在进行读取时,不等代.
 *       理由: read-read不会造成conflict.
 * 2. 当线程想要获取写入用的锁定时:
 *    <3>已经有线程在进行写入时,等待.
 *       理由: 不等待的话,会引起write-write conflict.
 *    <4>已经有线程在进行读取时,等待.
 *       理由: 不等待的话, 会引起read-write conflict.
 * </pre>
 * <strong>Create on : 2008-4-30<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public   final   class  ReadWriteLock  implements  Serializable  {

    
/**
     * <code>serialVersionUID</code>-注释
     
*/

    
private static final long serialVersionUID = -6877946865095666037L;
    
    
/**
     * <code>m_readingReaders</code>-正在进行读取操作的线程数量.
     
*/

    
private int m_readingReaders;
    
    
/**
     * <code>m_waitingWriters</code>-正在等待写操作的线程数量.
     
*/

    
private int m_waitingWriters;
    
    
/**
     * <code>m_writingWriters</code>-正在进行写操作的线程数量.
     
*/

    
private int m_writingWriters;
    
    
/**
     * <code>m_preferWrite</code>-是否优先写操作标志.true - 优先写操作,false - 正常顺序.
     
*/

    
private boolean m_preferWrite;
    
    
/**
     * 构造函数
     * 
@param preferWrite-是否优先写操作标志.true - 优先写操作,false - 正常顺序.
     
*/

    
public ReadWriteLock(boolean preferWrite) {
        
// TODO Auto-generated constructor stub
        this.m_preferWrite = preferWrite;
    }

    
    
/**
     * 获取读取锁.
     * 
@throws InterruptedException
     
*/

    
public synchronized void readLock() throws InterruptedException {
        
        
//如果正在写入的线程数>0 或者 (写优先 并且 等待写入的线程数 > 0 ) 则等待.
        if ( this.m_writingWriters > 0 || (this.m_preferWrite && this.m_waitingWriters > 0 ) ) {
            wait();
        }

        
        
this.m_readingReaders++;
    }

    
    
/**
     * 释放读取锁.
     * 
@throws InterruptedException
     
*/

    
public synchronized void readUnLock() throws InterruptedException{
        
        
this.m_readingReaders--;
        
this.m_preferWrite = true;
        notifyAll();
    }

    
    
/**
     * 获取写入锁.
     * 
@throws InterruptedException
     
*/

    
public synchronized void writeLock() throws InterruptedException{
        
        
//正在等待写入的计数器+1.
        this.m_waitingWriters++;
        
        
try {
            
            
//如果 ( 正在读取的线程数 > 0 或者 正在写入的线程数 > 0 ) 则等待.
            if ( this.m_readingReaders > 0 || this.m_writingWriters > 0 ) {
                wait();
            }

        }
 finally {
            
            
this.m_waitingWriters--;
        }

        
        
this.m_writingWriters++;
    }

    
    
/**
     * 释放写入锁.
     * 
@throws InterruptedException
     
*/

    
public synchronized void writeUnLock() throws InterruptedException{
        
this.m_writingWriters--;
        
this.m_preferWrite = false;
        notifyAll();
    }

    
    
}
// END CLASS OF ReadWriteLock.

3.3 ReadDataThread - 读取数据的线程类:
package  com.quf.study.thread.readwritelock;

/**
 * <strong>Title : ReaderThread<br></strong>
 * <strong>Description : </strong>读取数据的线程.<br> 
 * <strong>Create on : 2008-5-4<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public   final   class  ReadDataThread  extends  Thread  {
    
    
/**
     * <code>m_data</code>-注释
     
*/

    
private final ShareResource m_data;
    
    
/**
     * 构造函数
     * 
@param data
     
*/

    
public ReadDataThread(ShareResource data) {
        
this.m_data = data;
    }

    
    
/* (non-Javadoc)
     * @see java.lang.Thread#run()
     
*/

    
public void run(){
        
        
try {
            
whiletrue ) {
                
char[] t_readBuf = this.m_data.read();
                
                System.out.println(Thread.currentThread().getName()
+" reads "+String.valueOf(t_readBuf) );
            }

        }
 catch (InterruptedException e) {
            
// TODO: handle exception
        }

        
    }

}
// END CLASS OF ReadDataThread.

3.4 WriteDataThread - 写入数据的线程类:
package  com.quf.study.thread.readwritelock;

import  java.util.Random;

/**
 * <strong>Title : WriteDataThread<br></strong>
 * <strong>Description : </strong>写数据的线程.<br> 
 * <strong>Create on : 2008-5-4<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public   final   class  WriteDataThread  extends  Thread  {
    
    
/**
     * <code>s_random</code>-注释
     
*/

    
public static final Random s_random = new Random();
    
    
/**
     * <code>m_data</code>-注释
     
*/

    
private final ShareResource m_data;
    
    
/**
     * <code>m_filter</code>-注释
     
*/

    
private final String m_filter;
    
    
/**
     * <code>m_index</code>-注释
     
*/

    
private int m_index;
    
    
/**
     * 构造函数
     * 
@param data
     * 
@param filter
     
*/

    
public WriteDataThread(ShareResource data,String filter){
        
this.m_data = data;
        
this.m_filter = filter;
    }

    
    
/* (non-Javadoc)
     * @see java.lang.Thread#run()
     
*/

    
public void run() {
        
try {
            
while ( true ) {
                
char t_data = this.nextChar();
                
                
this.m_data.write(t_data);
                
                Thread.sleep(s_random.nextInt(
3000));
                
            }

        }
 catch (InterruptedException ie) {

        }

    }

    
    
/**
     * 获取下一个字符.
     * 
@return 下一个字符.
     
*/

    
private char nextChar() {
        
        
char t_c = this.m_filter.charAt(this.m_index);
        
        
this.m_index++;
        
        
if ( this.m_index >= this.m_filter.length() ) {
            
this.m_index = 0 ; 
        }

        
        
return t_c;
    }


}
// END CLASS OF WriteDataThread.

3.5 ReadWriteLockTest - 测试类:
package  com.quf.study.thread.readwritelock;

/**
 * <strong>Title : ReadWriteLockTest<br></strong>
 * <strong>Description : </strong>读写锁测试类.<br> 
 * <strong>Create on : 2008-5-4<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public   final   class  ReadWriteLockTest  {
    
    
public static void main(String[] args ) {
        
        
//创建数据对象.
        ShareResource t_data = new ShareResource(10);
        
        
new ReadDataThread(t_data).start();
        
new ReadDataThread(t_data).start();
        
new ReadDataThread(t_data).start();
        
new ReadDataThread(t_data).start();
        
new ReadDataThread(t_data).start();
        
new ReadDataThread(t_data).start();
        
        
new WriteDataThread(t_data,"ABCDEFGHIJKLMNOPQRSTUVWXYZ").start();
        
new WriteDataThread(t_data,"abcdefghijklmnopqrstuvwxyz").start();
        
    }

    
}
// END CLASS OF ReadWriteLockTest.


4. 扩展思考方向:

4.1 该模式利用同时读取而不会产生冲突的特性,提高了程序的性能.

4.2 该模式适合读取操作比较繁重的情况.

4.3 该模式适合读取比写入操作频繁时.

4.4 锁定的意义:

使用synchronized,可以获取实例的锁定.Java程序的每个实例各有一个"锁定",同一个实

例的锁定无法由两个以上的线程所获取.这是制定在JAVA语言规格里,实现在Java执行环

境里的机制.故称为物理性的锁定.Java程序无法去改变这种锁定的行为.

5. 相关知识:

4.1 Before/After Pattern:

前置处理(获取锁定)
try{

实际的操作.

} finally {

后续处理(解除锁定)

}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值