設計一個緩存系統  java多線程讀寫鎖的應用

package test;

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

/**
 * 設計一個緩存系統
 * 讀寫鎖的應用。
 * JDK1.5自帶的讀寫鎖特性,讀與讀不互斥,讀與寫互斥,寫與寫互斥。
 * 爲什麼要使用讀寫鎖?一句話概括那就是提高系統性能,如何提高呢?
 * 試想,對於所有對讀的操作是不需要線程互斥的,而如果方法內
 * 使用了synchronized關鍵字同步以達到線程安全,對於所有的線程不管是讀還是寫的操作都要同步。
 * 這時如果有大量的讀操作時就會又性能瓶頸。
 * 
 * 所以,當一個方法內有多個線程訪問,並且方法內有讀和寫讀操作時,
 * 提升性能最好的線程安全辦法時採用讀寫鎖的機制對讀寫互斥、寫寫互斥。這樣對於讀讀就沒有性能問題了
 * @author zhurudong
 *
 */
public class CacheTest {

	// 緩存的map
	private Map<String, Object> map = new HashMap<String, Object>();
	// 讀寫鎖對象
	private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	
	/**
	 * 從緩存中獲取數據的方法
	 * @param key
	 * @return
	 */
	public Object getData(String key) {
		readWriteLock.readLock().lock();//讀鎖,只對寫的線程互斥
		Object value = null;
		try {
			// 嘗試從緩存中獲取數據
			value = map.get(key);
			if (value == null) {
				readWriteLock.readLock().unlock();//發現目標值爲null,釋放掉讀鎖
				readWriteLock.writeLock().lock();//發現目標值爲null,需要取值操作,上寫鎖
				try {
					value = map.get(key);// 很嚴謹這一步。再次取目標值
					if (value == null) {//很嚴謹這一步。再次判斷目標值,防止寫鎖釋放後,後面獲得寫鎖的線程再次進行取值操作
						// 模擬DB操作
						value = new Random().nextInt(10000) + "test";
						map.put(key, value);
						
						System.out.println("db completed!");
					}
					readWriteLock.readLock().lock();//再次對讀進行鎖住,以防止寫的操作,造成數據錯亂
				} finally {
					/*
					 * 先加讀鎖再釋放寫鎖讀作用:
					 * 防止在43行出多個線程獲得寫鎖進行寫的操作,所以在寫鎖還沒有釋放前要上讀鎖
					 */
					readWriteLock.writeLock().unlock();
				}
			}
			
		} finally {
			readWriteLock.readLock().unlock();
		}
		return value;
	}
	
	/**
	 *  test main
	 * @param args
	 */
	public static void main(String[] args) {
		final CacheTest cache = new CacheTest();
		final String key = "user";
		for (int i = 0; i < 1000; i++) {
			new Thread(){
				public void run() {
					System.out.println(cache.getData(key));
				};
			}.start();
		}
	}
}

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