張孝祥讀寫鎖(學習筆記)

package cn.javaious.concurrence;

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final Queue3 q3 = new Queue3();
		for(int i=0;i<3;i++) {
			new Thread() {
				public void run() {
					for(;;) {
						q3.get();
					}
				}
			}.start();
			new Thread() {
				public void run() {
					for(;;) {
						q3.put(new Random().nextInt(1000));
					}
				};
			}.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) {
			// TODO Auto-generated catch block
			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 read data :"+data);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			rwl.writeLock().unlock();
		}
		
	}
}

操作系統中也有讀寫者經典問題:該問題最早由Dijkstra提出,用以演示他提出的信號量機制。要求設計在同一個進程地址空間內執行的兩個線程。生產者線程生產物品,然後將物品放置在一個空緩衝區中供消費者線程消費。消費者線程從緩衝區中獲得物品,然後釋放緩衝區。當生產者線程生產物品時,如果沒有空緩衝區可用,那麼生產者線程必須等待消費者線程釋放出一個空緩衝區。當消費者線程消費物品時,如果沒有滿的緩衝區,那麼消費者線程將被阻塞,直到新的物品被生產出來。

//已知mutex,wrt都是二進制信號量,初始化爲1,readcount是讀者的個數
//寫者
do
{
    wait(wrt);
     臨界區	//互斥共享的資源稱爲臨界資源,在程序中對臨界資源訪問的代碼稱爲臨界區。
     signal(wrt);
}while(true);
//讀者
do
{
    wait(mutex);	
    readcount++;
    if(readcount==1)
         wait(wrt);
     signal(mutex);
 
     wait(mutex);
     readcount--;
     if(readcount==0)
          signal(wrt);
         signal(mutex);
}while(true);


讀寫鎖api上的經典例子:

class CachedData {
   Object data;
   volatile boolean cacheValid;
   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();	//進來就開始讀,上讀鎖,不允許寫
     if (!cacheValid) {		//緩存不可用
        // Must release read lock before acquiring write lock
        rwl.readLock().unlock();	//緩存不可用,立馬釋放寫鎖,等待數據
        rwl.writeLock().lock();		//上寫鎖,不允許讀
        try {	
          // Recheck state because another thread might have
          // acquired write lock and changed state before we did.
          if (!cacheValid) {	//重新檢查緩存狀態,rwl.writeLock().lock()會造成線程阻塞,第一個線程成功寫入後,其後阻塞的線程需要再次判斷
            data = ...
            cacheValid = true;
          }
          // Downgrade by acquiring read lock before releasing write lock
          rwl.readLock().lock();	//降級通過在釋放寫鎖之前獲取讀鎖(鎖降級)
        } finally {
          rwl.writeLock().unlock(); // Unlock write, still hold read	釋放寫鎖,保持讀鎖狀態
        }
     }

     try {
       use(data);
     } finally {
       rwl.readLock().unlock();	//釋放讀鎖
     }
   }
 }


關於鎖降級,可以參考:http://www.cnblogs.com/hzhuxin/archive/2012/11/01/2749341.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章