1. 程式人生 > >JAVA 併發程式設計-讀寫鎖之模擬快取系統(十一)

JAVA 併發程式設計-讀寫鎖之模擬快取系統(十一)

    在多執行緒中,為了提高效率有些共享資源允許同時進行多個讀的操作,但只允許一個寫的操作,比如一個檔案,只要其內容不變可以讓多個執行緒同時讀,不必做排他的鎖定,排他的鎖定只有在寫的時候需要,以保證別的執行緒不會看到資料不完整的檔案。這時候就需要使用讀寫鎖。

/**
 * 簡單讀寫鎖demo
 * @author hejingyuan
 *
 */
public class ReadWriteLockTest {
	public static void main(String[] args) {
		final Queue3 q3 = new Queue3();
		//建立幾個執行緒
		for(int i=0;i<3;i++)
		{
			new Thread(){
				public void run(){
					while(true){
						q3.get();						
					}
				}
				
			}.start();
			
			new Thread(){
				public void run(){
					while(true){
						q3.put(new Random().nextInt(10000));
					}
				}			
				
			}.start();
			
		}
		
	}
}

class Queue3{
	private Object data = null;//共享資料,只能有一個執行緒能寫該資料,但可以有多個執行緒同時讀該資料
	//讀寫鎖
	ReadWriteLock rwl = new ReentrantReadWriteLock();
	//讀資料
	public void get(){
		rwl.readLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to read data!");
			Thread.sleep((long)(Math.random()*1000));
			System.out.println(Thread.currentThread().getName() + "have read data :" + data);			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.readLock().unlock();
		}
	}
	//寫資料
	public void put(Object data){

		rwl.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to write data!");					
			Thread.sleep((long)(Math.random()*1000));
			this.data = data;		
			System.out.println(Thread.currentThread().getName() + " have write data: " + data);					
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.writeLock().unlock();
		}
		
	
	}
}


執行結果:

Thread-0 be ready to readdata!

Thread-2 be ready to readdata!

Thread-2have read data:null

Thread-0have read data:null

Thread-1 be ready towrite data!

Thread-1 have write data:1021

Thread-1 be ready towrite data!

Thread-1 have write data:2887

看到這裡不免有人會問,既然讀的時候可以多人訪問,那麼為什麼還要加讀鎖呢?

答:當然要加鎖了,否則在寫時去讀,可能不正確-(寫的時候不能去讀)

讀寫鎖-模擬快取系統實現:

public class CacheDemo {

	private Map<String, Object> cache = new HashMap<String, Object>();
	public static void main(String[] args) {
		

	}

	//定義讀寫鎖
	private ReadWriteLock rwl = new ReentrantReadWriteLock();
	//讀資料,使用讀鎖
	public  Object getData(String key){
		//新增讀鎖
		rwl.readLock().lock();
		Object value = null;
		try{
			value = cache.get(key);
			if(value == null){
				//釋放讀鎖
				rwl.readLock().unlock();
				//加上寫鎖
				rwl.writeLock().lock();
				try{
					//假設三個執行緒同時去獲取寫鎖,我們知道只有第一個執行緒能夠獲取
                    //那麼其他兩個執行緒只有等了,如果第一個執行緒按流程執行完後,剛才的兩個執行緒可以得到寫鎖了,
                    //然後接著就可以修改資料了(賦值).所以加上判斷!
					if(value==null){//為什麼還要判斷?
						value = "aaaa";//實際是去queryDB();
					}
				}finally{
					//釋放寫鎖
					rwl.writeLock().unlock();
				}
				rwl.readLock().lock();
			}
		}finally{
			rwl.readLock().unlock();
		}
		return value;
	}
}


總結:

    讀寫鎖的作用為,當我們加上寫鎖時,其他執行緒被阻塞,只有一個寫操作在執行,當我們加上讀鎖後,它是不會限制多個讀執行緒去訪問的。也就是getput之間是互斥的,put與任何執行緒均為互斥,但是getget執行緒間並不是互斥的。其實加讀寫鎖的目的是同一把鎖的讀鎖既可以與寫鎖互斥,讀鎖之間還可以共享。