我们有时会遇到对同一个内存区域如数组或者链表进行多线程读写的情况,一般来说有以下几种处理方式:
1.不加任何限制,多见于读取写入都很快的情况,但有时也会出现问题.
2.对读写函数都加以同步锁,比如使用singleton模式,这下问题是没了,但效率也下去了,比如说两个读取线程不是非要排队进入不可.
3.读写锁,安全和效率都得到了解决,特别合适读线程多于写线程的情况.也就是下面将要展现的模式.
读写锁的本意是分别对读写状态进行互斥区分,有互斥时才加锁,否则放行.互斥的情况有:
1.读写互斥.
2.写写互斥.
不互斥的情况是:读读,这种情况不该加以限制.
我们只要让锁对象知道当前读写状态就可以了,再根据情况进行锁定和解锁,然后再分情况进行锁定.请看代码
代码如下:
DataLib类,注意其中try...finally 的写法,它保证了加锁解锁过程是成对调用的:
package com.sitinspring.readwritelock;
import java.util.ArrayList;
import java.util.List;
/** *//**
* 数据仓库类,用于保存数据
*
* @author sitinspring(junglesong@gmail.com)
*
*/
public class DataLib {
private List<String> datas;
private ReadWriteLock lock;
public DataLib() {
datas = new ArrayList<String>();
lock = new ReadWriteLock();
}
// 写入数据,这时不能读取
public void writeData(List<String> newDatas) {
try {
lock.writeLock();
Test.sleep(2);
datas=newDatas;
} finally {
lock.writeUnlock();
}
}
// 读取数据,这时不能写入
public List<String> readData() {
try {
lock.readLock();
Test.sleep(1);
return datas;
} finally {
lock.readUnlock();
}
}
}
ReadWriteLock类,很重要:
package com.sitinspring.readwritelock;
/** *//**
* 读写锁,用于线程控制
* @author sitinspring(junglesong@gmail.com)
*
*/
public class ReadWriteLock{
// 读状态
private boolean isRead;
// 写状态
private boolean isWrite;
public synchronized void readLock(){
// 有写入时读取线程停止
while(isWrite){
try{
System.out.println("有线程在进行写入,读取线程停止,进入等待状态");
wait();
}
catch(InterruptedException ex){
ex.printStackTrace();
}
}
System.out.println("设定锁为读取状态");
isRead=true;
}
public synchronized void readUnlock(){
System.out.println("解除读取锁");
isRead=false;
notifyAll();
}
public synchronized void writeLock(){
// 有读取时读取线程停止
while(isRead){
try{
System.out.println("有线程在进行读取,写入线程停止,进入等待状态");
wait();
}
catch(InterruptedException ex){
ex.printStackTrace();
}
}
// 有写入时写入线程也一样要停止
while(isWrite){
try{
System.out.println("有线程在进行写入,写入线程停止,进入等待状态");
wait();
}
catch(InterruptedException ex){
ex.printStackTrace();
}
}
System.out.println("设定锁为写入状态");
isWrite=true;
}
public synchronized void writeUnlock(){
System.out.println("解除写入锁");
isWrite=false;
notifyAll();
}
}
Writer类:
package com.sitinspring.readwritelock;
import java.util.ArrayList;
import java.util.Random;
/** *//**
* 用于读取文件,写入数据仓库
* @author sitinspring(junglesong@gmail.com)
*
*/
public class Writer implements Runnable{
private DataLib dataLib;
private static final Random random=new Random();
private String[] mockDatas={"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
public Writer(DataLib dataLib,String[] mockDatas){
this.dataLib=dataLib;
this.mockDatas=mockDatas;
Thread thread=new Thread(this);
thread.start();
}
public void run(){
while(true){
Test.sleep(random.nextInt(3));
int startIndex=random.nextInt(mockDatas.length);
ArrayList<String> newDatas=new ArrayList<String>();
for(int i=startIndex;i<mockDatas.length;i++){
newDatas.add(mockDatas[i]);
}
dataLib.writeData(newDatas);
}
}
}
Reader类:
package com.sitinspring.readwritelock;
import java.util.List;
import java.util.Random;
/** *//**
* 用于从数据仓库中得到数据
* @author sitinspring(junglesong@gmail.com)
*
*/
public class Reader implements Runnable{
private DataLib dataLib;
private static final Random random=new Random();
public Reader(DataLib dataLib){
this.dataLib=dataLib;
Thread thread=new Thread(this);
thread.start();
}
public void run(){
while(true){
Test.sleep(random.nextInt(2));
List<String> datas=dataLib.readData();
System.out.print(">>取得数组为:");
for(String data:datas){
System.out.print(data+",");
}
System.out.print("\n");
}
}
}
测试类:
package com.sitinspring.readwritelock;
/** *//**
* main函数所在类
* @author sitinspring(junglesong@gmail.com)
*
*/
public class Test{
public static void main(String[] args){
DataLib dataLib=new DataLib();
String[] mockDatas1={"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
Writer writer1=new Writer(dataLib,mockDatas1);
String[] mockDatas2={"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
Writer writer2=new Writer(dataLib,mockDatas2);
Reader reader1=new Reader(dataLib);
Reader reader2=new Reader(dataLib);
Reader reader3=new Reader(dataLib);
}
// 用于延时
public static void sleep(int sleepSecond){
try{
Thread.sleep(sleepSecond*1000);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
测试结果:
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
解除读取锁
>>取得数组为:
设定锁为读取状态
有线程在进行读取,写入线程停止,进入等待状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
设定锁为写入状态
>>取得数组为:
解除读取锁
>>取得数组为:
解除读取锁
>>取得数组为:
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
解除读取锁
>>取得数组为:亥,
解除读取锁
>>取得数组为:亥,
解除读取锁
>>取得数组为:亥,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
>>取得数组为:乙,丙,丁,戊,己,庚,辛,壬,癸,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
>>取得数组为:申,酉,戌,亥,
解除读取锁
>>取得数组为:申,酉,戌,亥,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
>>取得数组为:丁,戊,己,庚,辛,壬,癸,
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
>>取得数组为:亥,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除读取锁
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
>>取得数组为:亥,
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:丁,戊,己,庚,辛,壬,癸,
解除读取锁
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:丁,戊,己,庚,辛,壬,癸,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行读取,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
>>取得数组为:巳,午,未,申,酉,戌,亥,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:巳,午,未,申,酉,戌,亥,
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
解除读取锁
>>取得数组为:戌,亥,
解除读取锁
>>取得数组为:戌,亥,
解除读取锁
>>取得数组为:戌,亥,
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
有线程在进行读取,写入线程停止,进入等待状态
设定锁为读取状态
解除读取锁
>>取得数组为:丙,丁,戊,己,庚,辛,壬,癸,
解除读取锁
>>取得数组为:丙,丁,戊,己,庚,设定锁为写入状态
辛,壬,癸,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:丙,丁,戊,己,庚,辛,壬,癸,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
>>取得数组为:癸,
有线程在进行写入,写入线程停止,进入等待状态
解除读取锁
>>取得数组为:癸,
解除读取锁
>>取得数组为:癸,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
解除读取锁
>>取得数组为:戊,己,庚,辛,壬,癸,
解除读取锁
>>取得数组为:戊,己,庚,辛,壬,癸,
解除读取锁
>>取得数组为:戊,己,庚,辛,壬,癸,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
>>取得数组为:乙,丙,丁,戊,己,庚,辛,壬,癸,
解除读取锁
>>取得数组为:乙,解除读取锁
>>取得数组为:乙,丙,丁,戊,己,庚,辛,壬,癸,
丙,丁,戊,己,庚,辛,有线程在进行写入,写入线程停止,进入等待状态
壬,癸,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
解除读取锁
>>取得数组为:庚,辛,壬,癸,
解除读取锁
>>取得数组为:庚,辛,壬,癸,
解除读取锁
>>取得数组为:庚,辛,壬,癸,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
>>取得数组为:亥,
有线程在进行写入,写入线程停止,进入等待状态
解除读取锁
有线程在进行写入,写入线程停止,进入等待状态
>>取得数组为:亥,
解除读取锁
有线程在进行写入,写入线程停止,进入等待状态
>>取得数组为:有线程在进行写入,读取线程停止,进入等待状态
亥,
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
解除读取锁
>>取得数组为:癸,
解除读取锁
>>取得数组为:癸,
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:癸,
解除写入锁
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
>>取得数组为:申,酉,戌,亥,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
有线程在进行读取,写入线程停止,进入等待状态
设定锁为读取状态
解除读取锁
>>取得数组为:癸,
设定锁为写入状态
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
>>取得数组为:癸,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:癸,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
>>取得数组为:戊,己,庚,辛,壬,癸,
解除读取锁
>>取得数组为:戊,己,庚,辛,壬,癸,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
>>取得数组为:亥,
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除读取锁
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
>>取得数组为:亥,
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行读取,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除读取锁
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:丁,戊,己,庚,辛,壬,癸,
解除读取锁
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:丁,戊,己,庚,辛,壬,癸,
解除写入锁
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,写入线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
解除读取锁
>>取得数组为:癸,
解除读取锁
>>取得数组为:癸,
解除读取锁
>>取得数组为:癸,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行读取,写入线程停止,进入等待状态
解除读取锁
有线程在进行写入,读取线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
>>取得数组为:辰,巳,午,未,申,酉,戌,亥,
有线程在进行写入,写入线程停止,进入等待状态
有线程在进行写入,读取线程停止,进入等待状态
解除写入锁
设定锁为读取状态
设定锁为读取状态
设定锁为写入状态
有线程在进行写入,读取线程停止,进入等待状态
代码下载:
http://www.blogjava.net/Files/sitinspring/ReadWriteLock20071021115927.rar