한가 할 때 자바 의 부 드 러 운 인용 으로 짝 퉁 캐 시 를 썼 다.

오늘 항 저 우의 날 씨 는 매우 덥 고 35 도 입 니 다. 이것 은 나 에 게 경 명 을 요구 하 는 것 입 니 다. 게다가 최근 에 기분 이 매우 나 빠 서 scala 의 물건 도 한동안 보지 않 고 쓰 지 않 았 습 니 다.오늘 회 사 는 개가 짖 고 결혼 하 는 사람 도 있 고 아이 가 우 는 소리 도 있 습 니 다. 항 저 우 전기 제한 회사 도 있 고 에어컨 도 꺼 졌 습 니 다. XXX 때문에 해외 사이트 에 올 라 완전히 무 너 졌 기 때문에 구 글 이 없 는 프로그래머 가 고구 마 를 파 는 것 보다 못 하 다 고 생각 합 니 다.
자, 잡담 은 그만 하고 본론 으로 들 어가 자. 자바 의 인용 은 StrongReference, SoftReference, WeakReference, PhantomReference 로 나 뉜 다.이 몇 가지 인용 은 서로 다른 사용 장면 이 있 는데 평소에 우리 가 가장 자주 사용 하 는 것 은 바로 StrongReference 이다. 즉, 이와 같은 인용 이다. 
Object obj = new Object();
  이러한 인용 은 이른바 강 한 인용 이다. 이 대상 이 가리 키 는 것 을 인용 하지 않 고 살 아 있 는 스 레 드 가 접근 할 수 없다 면 (쓰레기 외 딴 섬 에 대해 서 는) 그 는 회수 되 고 이 대상 이 강 한 인용 으로 가리 키 며 메모리 가 다 소모 되면 OOM 쓰레기 수집 기 를 던 져 도 이 대상 을 회수 하지 않 을 것 이다.
한편, SoftReference 의 경우 GC 에 의 해 회수 되 는 조건 이 그리 엄격 하지 않 습 니 다. 만약 에 한 대상 이 현재 가장 강 한 인용 이 소프트 인용 이 고 JVM 의 메모리 가 충분 하 다 면 쓰레기 회수 기 는 회수 되 지 않 을 것 입 니 다.메모리 가 부족 한 경우 에 만 GC 는 소프트 참조 가 가리 키 는 대상 을 회수 할 수 있 습 니 다. 이 특징 을 통 해 소프트 인용 은 고속 캐 시 를 만 들 고 LRU 정책 에 맞 추 는 것 이 좋 습 니 다.오늘 은 내 가 하나 써 서 놀 게.
package com.blackbeans.example;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;

/**
 * 
 * @author blackbeans
 * @param <K>
 * @param <T>
 */
public class ReferenceCache<K,T> {
	
	
	private HashMap<K, InnerReference<K,T>>  cachedReference = new HashMap<K, InnerReference<K,T>>(1024);
	private final  ReferenceQueue<T>  referenceQueue ;
	
	private final ObjectNotFoundHandler<K,T> existsHandler;
	
	/**
	 *              
	 * @author blackbeans
	 *
	 * @param <K>
	 * @param <T>
	 */
	private static class DefaultObjectNotFoundHandler<K,T> implements ObjectNotFoundHandler<K,T>
	{
		@Override
		public T queryAndCached(K key) {
			// TODO Auto-generated method stub
			return null;
		}
		
	}
	
	/**
	 *            
	 * @author blackbeans
	 *
	 * @param <K>
	 * @param <T>
	 */
	public static interface ObjectNotFoundHandler<K,T>
	{
		public T queryAndCached(K key);
		
	}
	
	
	private static class InnerReference<K,T> extends SoftReference<T>{
		private final K key ;
		public InnerReference(K key,T reference,ReferenceQueue<T> queue) {
			super(reference,queue);
			this.key = key;
		}
		
		public K getKey()
		{
			return this.key;
		}
	} 
	
	
	public ReferenceCache(ObjectNotFoundHandler<K,T> handler)
	{
		this.referenceQueue = new ReferenceQueue<T>();
		this.existsHandler = handler == null ? new DefaultObjectNotFoundHandler<K,T>() : handler;
	}
	
	
	public ReferenceCache()
	{
		this(null);
	}
	
	public void cachedReference(K key,T reference)
	{
		/**
		 *                 reference
		 */
		cleanReference(key);
		if(!this.cachedReference.containsKey(key))
		{
			this.cachedReference.put(key, new InnerReference<K,T>(key,reference, this.referenceQueue));
		}
	}
	
	public T getReference(K key)	{
		
		T obj = null;
		
		if(this.cachedReference.containsKey(key)){
			obj =  this.cachedReference.get(key).get();
		}
		
		if(null == obj)
		{
			/**
			 *            ,       
			 */
			obj = this.existsHandler.queryAndCached(key);
			this.cachedReference(key, obj);
			return obj;
		}
		return obj;
		
	}

	@SuppressWarnings("unchecked")
	private void cleanReference(K key) {
		//    key             
		if (this.cachedReference.containsKey(key)
				&& this.cachedReference.get(key).get() == null)
			this.cachedReference.remove(key);
		T obj = null;
		//    Key                Key
		Reference<? extends T> reference = null;
		while((reference = this.referenceQueue.poll()) != null)
		{
			obj = reference.get();
			if(obj == null)
			{
				this.cachedReference.remove(((InnerReference<K, T>)reference).getKey());
			}
		}
	}
	
	
	public void clearALLObject()
	{
		this.cachedReference.clear();
		System.gc();
	}
	
}

   전체 구현 에서 대상 의 인용 을 내 가 정의 한 key - > 소프트 인용 map 에 넣 은 다음 cache 에서 대상 을 가 져 올 때마다 먼저 key 를 통 해 map 를 조회 하여 대상 의 소프트 인용 을 얻 고 존재 하면 소프트 인용 을 통 해 대상 을 가 져 오 려 고 시도 합 니 다. 존재 하지 않 으 면 소프트 인용 이 가리 키 는 대상 이 회수 되면 우 리 는 내 장 된 handler 를 호출 합 니 다.대상 을 다시 만 들 고 cache 대상 의 소프트 참조 입 니 다.
제 실현 에서 저 는 사용자 에 게 대상 이 회수 되 었 을 때의 처리 handler 를 제공 하여 사용자 가 이 handler 를 통 해 대상 을 재 구성 하도록 지도 하려 고 했 습 니 다. 캐 시 대상 은 유연성 이 매우 큽 니 다.
부 드 럽 게 인 용 된 캐 시가 LRU 정책 으로 완벽 해 지면 LRU 정책 을 사용자 정의 할 수 있 는 Processor 를 제공 하 는 것 이 부족 하 다.사실 간단 합 니 다. HashMap 을 링크 드 HashMap 으로 바 꾸 어 removeEldest 방법 을 실현 하고 방법 에서 사용자 정의 LRU 프로 세 서 를 호출 하면 됩 니 다.
        비용 을 줄 이기 위해 서, 나 는 캐 치 할 때마다 이미 효력 을 잃 은 소프트 인용 을 정리 했다.왜 Reference Queue 가 있 냐 고 물 어보 실 수도 있어 요.사실은 이 렇 습 니 다. 소프트 인용 이 인용 한 대상 이 회수 되 었 다 고 생각 한 후에 대상 의 소프트 인용 대상 은 회수 되 었 습 니 다. 그러나 다른 대상 인 SoftReference 를 도 입 했 습 니 다. 하 나 를 가 져 가면 하나 더 남 겨 야 하 는 지 생각 하지 않 습 니 다. 소프트 인용 대상 이 회수 되면 이 소프트 인용 자체 가 이 quue 에 추가 되 어 회 수 를 기다 리 고 있 습 니 다.이 quue 를 편리 하 게 해서 소프트 인용 을 가 져 와 map 에서 만 료 된 소프트 인용 을 가 져 옵 니 다.
이로써 할 말 도 다 했 고 하지 말 아야 할 말 도 했 습 니 다. 결말 이 매우 갑 작 스 러 우 니 양해 해 주 십시오!
 

좋은 웹페이지 즐겨찾기