我們有時會遇到對同一個內存區域如數組或者鏈表進行多線程讀寫的情況,一般來說有以下幾種處理方式:
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.tkk7.com/Files/sitinspring/ReadWriteLock20071021115927.rar