1. 程式人生 > >Ehcache高併發在專案中的應用

Ehcache高併發在專案中的應用

我們在專案開發中,有些資料常常用到,而又不需要經常去更新它,我們就會想到了使用快取來儲存這些資料,已提高我們對這些資料的讀取速度,因此本文使用ehcache來解決這個問題,EhcacheUtil 能有效的防止高併發。

1、EhcacheUtil 類

/**
 * 高併發解析:
 * 1、當一個執行緒獲取了某一Key的Read鎖之後,其它執行緒獲取針對於同一個Key的Read鎖不會受到限制,
 * 但其它執行緒(包括獲取了該Key的Read鎖的執行緒)如果想獲取針對同一個Key的Write鎖就不行,它需要等到針對於該Key的Read鎖釋放後才能獲取其Write鎖;
 * 2、當一個執行緒獲取了某一Key的Write鎖之後,其它執行緒獲取同一個Key的Read鎖或者Write鎖的請求將等待針對於該Key的Write鎖釋放後才能繼續進行,
 * 但是同一個執行緒獲取該Key對應的Read鎖或者Write鎖將不需要等待。
 * 獲取了對應的鎖之後,不再需要該鎖後釋放該鎖,以免引起死鎖。
 */
public class EhcacheUtil {

	private static final String PATH = "/ehcache.xml";
	
	private static final String CACHE_NAME = "productEhcache";

	private CacheManager manager;

	private static EhcacheUtil ehCache;

	private EhcacheUtil(String path) {
		URL url = getClass().getResource(path);
		manager = CacheManager.create(url);
	}

	/**
	 * 獲取快取例項,配置檔案路徑“src/ehcache.xml”
	 * @return
	 */
	public static EhcacheUtil getInstance() {
		if (ehCache == null) {
			ehCache = new EhcacheUtil(PATH);
		}
		return ehCache;
	}
	
	/**
	 * 儲存鍵值到預設的快取裡面
	 * @param key 鍵名
	 * @param value 鍵值
	 */
	public void put(String key, Object value) {
		put(CACHE_NAME, key, value);
	}

	/**
	 * 儲存鍵值到指定的快取裡面
	 * @param cacheName 快取名稱
	 * @param key 鍵名
	 * @param value 鍵值
	 */
	public void put(String cacheName, String key, Object value) {
		Cache cache = manager.getCache(cacheName);
		cache.acquireWriteLockOnKey(key);
		try {
			Element element = new Element(key, value);
			cache.put(element);
		} finally {
			cache.releaseWriteLockOnKey(key);
		} 
	}

	/**
	 * 從預設的快取裡面獲取鍵值
	 * @param key 鍵名
	 */
	public Object get(String key) {
		return get(CACHE_NAME, key);
	}

	/**
	 * 從指定的快取裡面獲取鍵值
	 * @param cacheName 快取名稱
	 * @param key 鍵名
	 */
	public Object get(String cacheName, String key) {
		Cache cache = manager.getCache(cacheName);
		cache.acquireReadLockOnKey(key);
		Element element = null;
		try{
			element = cache.get(key);
		} finally {
			cache.releaseReadLockOnKey(key);
		} 
		return element == null ? null : element.getObjectValue();
	}

	/**
	 * 從預設的快取裡面刪除鍵值
	 * @param key 鍵名
	 */
	public void remove(String key) {
		remove(CACHE_NAME, key);
	}

	/**
	 * 從指定的快取裡面刪除鍵值
	 * @param cacheName 快取名稱
	 * @param key 鍵名
	 */
	public void remove(String cacheName, String key) {
		Cache cache = manager.getCache(cacheName);
		cache.remove(key);
	}
	
}
2、ehcache.xml配置檔案,放到src根目錄下面
<?xml version="1.0" encoding="UTF-8"?>
<!--   
快取配置 
  timeToIdleSeconds 當快取閒置n秒後銷燬。
  timeToLiveSeconds 當快取存活n秒後銷燬。
  name:快取名稱。 
  maxElementsInMemory:快取最大個數。 
  eternal:物件是否永久有效,一但設定了,timeout將不起作用。 
  timeToIdleSeconds:設定物件在失效前的允許閒置時間(單位:秒)。僅當eternal=false物件不是永久有效時使用,可選屬性,預設值是0,也就是可閒置時間無窮大。 
  timeToLiveSeconds:設定物件在失效前允許存活時間(單位:秒)。最大時間介於建立時間和失效時間之間。僅當eternal=false物件不是永久有效時使用,預設是0.,也就是物件存活時間無窮大。 
  overflowToDisk:當記憶體中物件數量達到maxElementsInMemory時,Ehcache將會物件寫到磁碟中。 
  diskSpoolBufferSizeMB:這個引數設定DiskStore(磁碟快取)的快取區大小。預設是30MB。每個Cache都應該有自己的一個緩衝區。 
  maxElementsOnDisk:硬碟最大快取個數。 
  diskPersistent:是否快取虛擬機器重啟期資料 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. 
  diskExpiryThreadIntervalSeconds:磁碟失效執行緒執行時間間隔,預設是120秒。 
  memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理記憶體。預設策略是LRU(最近最少使用)。你可以設定為FIFO(先進先出)或是LFU(較少使用)。 
  clearOnFlush:記憶體數量最大時是否清除。 
-->	 
<ehcache>
	<diskStore path="java.io.tmpdir" />   
	<defaultCache maxElementsInMemory="500" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="1200" overflowToDisk="true" />
    <cache name="testEhcache" maxElementsInMemory="150" eternal="false" timeToLiveSeconds="36000" timeToIdleSeconds="3600" overflowToDisk="true"/>  
    <cache name="productEhcache" maxElementsInMemory="500" memoryStoreEvictionPolicy="LRU" eternal="true" diskSpoolBufferSizeMB="1024" overflowToDisk="true"/>  
</ehcache>  
3、EhcacheTest測試類
public class EhcacheTest {

	//新建ehcache例項
	private static EhcacheUtil ehcache = EhcacheUtil.getInstance();
	
	public static void main(String[] args) {
		setProductData();
		ProductDto pd = (ProductDto)ehcache.get(Constant.PRODUCT_MAP_CACHE_NAME+1);
		System.out.println(pd);
		ehcache.remove(Constant.PRODUCT_MAP_CACHE_NAME+1);
		pd = (ProductDto)ehcache.get(Constant.PRODUCT_MAP_CACHE_NAME+1);
		System.out.println(pd);
	}
	
	public static void setProductData(){
		//構造資料
		int sizeProduct = 100000;
		//List<ProductDto> productList = new ArrayList<ProductDto>();
		for (int j = 0; j < sizeProduct; j++) {
//			ProductDto product = new ProductDto();
//			product.setId(j);
//			product.setProductName("產品名稱"+j);
//			//productList.add(product);
//			ehcache.put(Constant.PRODUCT_MAP_CACHE_NAME+j, product);
			ehcache.put(Constant.PRODUCT_MAP_CACHE_NAME+j, j);
		}
		//把map放到ehcache中
		//ehcache.put(Constant.PRODUCT_MAP_CACHE_NAME, productList);
	}
	
	@SuppressWarnings("unchecked")
	public static List<ProductDto> getProductData(){
		return (List<ProductDto>)ehcache.get(Constant.PRODUCT_MAP_CACHE_NAME);
	}
	
	public static void deleteProductData(int index){
		List<ProductDto> productList = getProductData();
		productList.remove(productList.get(index));
		ehcache.put(Constant.PRODUCT_MAP_CACHE_NAME, productList);
	}
	
	public static void addProductData(int index){
		List<ProductDto> productList = getProductData();
		ProductDto product = new ProductDto();
		product.setId(index);
		product.setProductName("產品名稱"+index);
		productList.add(product);
		ehcache.put(Constant.PRODUCT_MAP_CACHE_NAME, productList);
	}
	
	public static void showProductData(){
		List<ProductDto> productList = getProductData();
		System.out.println("---------------------");
		for (ProductDto productDto : productList) {
			System.out.println(productDto);
		}
	}
	
}
4、ProductDto實體類
public class ProductDto implements java.io.Serializable {
	private static final long serialVersionUID = 1L;
	private Integer id;//id
	private String productName;//產品名稱
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	
	public String toString(){
		return this.getId()+" ,name:"+this.getProductName();
	}

}
5、Constant靜態變數類
public class Constant {
	/**
	 * 產品MAP
	 */
	public static final String PRODUCT_MAP_CACHE_NAME = "productMap";
}