1. 模式描述:
大家想看就看把, 但是看的时候不能写哦.
Read-Write Lock Pattern将读取与写入分开处理. 在读取数据之前,必须获取用来读取的锁定.
而要写入的时候,则必须获取用来写入的锁定.
因为读取的时候,实例的状态不会改变,所以,就算有多个线程在同时读取也没有关系.但,有人在读
取的时候,不可做写入的操作.
写入的时候,实例的状态就会改变,于是,当有一个线程在写入的时候,其他的线程不可以进行读取或
写入.
一般来说,进行共享互斥会使程序性能变差,但将写入的共享互斥与读取的共享互斥分开思考,就可
以提升程序的性能.
2. 参与者:
2.1. Reader(读取者)参与者.
2.2. Writer(写入者)参与者.
2.3. SharedResource(共享资源)参与者.
2.4. ReadWriteLock(读写用锁定)参与者.
3. 示例程序:
3.1 ShareResource类 - SharedResource(共享资源)参与者:
3.2 ReadWriteLock类 - 读写锁:
3.3 ReadDataThread - 读取数据的线程类:
3.4 WriteDataThread - 写入数据的线程类:
3.5 ReadWriteLockTest - 测试类:
4. 扩展思考方向:
4.1 该模式利用同时读取而不会产生冲突的特性,提高了程序的性能.
4.2 该模式适合读取操作比较繁重的情况.
4.3 该模式适合读取比写入操作频繁时.
4.4 锁定的意义:
5. 相关知识:
4.1 Before/After Pattern:
前置处理(获取锁定)
try{
实际的操作.
} finally {
后续处理(解除锁定)
}
大家想看就看把, 但是看的时候不能写哦.
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.
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.
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 {
while( true ) {
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.
/**
* <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 {
while( true ) {
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.
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.
/**
* <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程序无法去改变这种锁定的行为.
例的锁定无法由两个以上的线程所获取.这是制定在JAVA语言规格里,实现在Java执行环
境里的机制.故称为物理性的锁定.Java程序无法去改变这种锁定的行为.
5. 相关知识:
4.1 Before/After Pattern:
前置处理(获取锁定)
try{
实际的操作.
} finally {
后续处理(解除锁定)
}