一个简单的学习多线程缓存的demo

一个简单的学习多线程缓存的demo:
//计算
public interface Computable<A, V> {
	V compute(A arg) throws InterruptedException;
}



/** 第一种最简单实现:采用HashMap,直接在compute()方法上加锁这种构建缓存的方式有很大问题,
 * 如果compute执行时间很长那么有很多线程都要排队等待,那么此时效率可能比没有缓存还低.*/
public class Momizer1<A, V> implements Computable<A, V>{
   
	private final Map<A, V> cacheMap = new HashMap<A, V>();
	private final Computable<A, V> computable;
	public Momizer1(Computable<A, V> computable){
		this.computable = computable;
	}
	@Override
	public synchronized V compute(A arg) throws InterruptedException {
		V v = cacheMap.get(arg);
		if(v==null){
			v = computable.compute(arg);
			cacheMap.put(arg, v);
		}
		
		return v;
	}

}




/** 第二种实现:用ConcurrentHashMap代替HashMap,由于ConcurrentHashMap是线程安全的且效率比较高,所以比第一种效率高.
 * 但是这种方式会产生重复计算问题,假如传入相同的值,因为线程间不知道是否已经开始计算,所以都会去计算。*/
public class Momizer2<A, V> implements Computable<A, V>{
   
	private final ConcurrentHashMap<A, V> cacheMap = new ConcurrentHashMap<A, V>();
	private final Computable<A, V> computable;
	public Momizer2(Computable<A, V> computable){
		this.computable = computable;
	}
	@Override
	public  V compute(A arg) throws InterruptedException {
		V v = cacheMap.get(arg);
		if(v==null){
			v = computable.compute(arg);
			cacheMap.put(arg, v);
		}
		
		return v;
	}

}


/** 第三种实现:将长时间的计算过程用FutureTask替代,如果FutureTask计算结果完毕,那么直接返回结果,
 * 如果没有那么久阻塞等待返回结果.但是这种方式还是没有解决重复计算问题,虽然概率远小于第二种方式.因为
 * 存在符合操作若没有则添加*/
public class Momizer3<A, V> implements Computable<A, V>{
   
	private final ConcurrentHashMap<A, FutureTask<V>> cacheMap = new ConcurrentHashMap<A, FutureTask<V>>();
	private final Computable<A, V> computable;
	public Momizer3(Computable<A, V> computable){
		this.computable = computable;
	}
	@Override
	public  V compute(final A arg) throws InterruptedException {
		FutureTask<V> futureTask = cacheMap.get(arg);
		//
		if(futureTask==null){
			Callable<V> callable = new Callable<V>() {

				@Override
				public V call() throws Exception {
					return computable.compute(arg);
				}
			};
			
			FutureTask<V> f  = new FutureTask<>(callable);
			futureTask = f;
			cacheMap.put(arg, f);
			f.run();
			
			/*futureTask  = new FutureTask<>(callable);
			cacheMap.put(arg, futureTask);
			futureTask.run();*/
		}
		
		try {
			return futureTask.get();
		} catch (ExecutionException e) {
			throw new RuntimeException();
		}
	}

}


/**
 * 第四种实现:利用ConcurrentHashMap的putIfAbsent方法实现,这个方法相当于如果有就返回值,没有就返回null并讲值放入map. 
 */
public class Momizer4<A, V> implements Computable<A, V> {

	private final ConcurrentHashMap<A, FutureTask<V>> cacheMap = new ConcurrentHashMap<A, FutureTask<V>>();
	private final Computable<A, V> computable;

	public Momizer4(Computable<A, V> computable) {
		this.computable = computable;
	}

	@Override
	public V compute(final A arg) throws InterruptedException {
		while(true){
			FutureTask<V> f = cacheMap.get(arg);
			if(f==null){
				Callable<V> callable = new Callable<V>() {

					@Override
					public V call() throws Exception {
						return computable.compute(arg);
					}
					
				};
				FutureTask<V> ft = new FutureTask<>(callable);
				f = cacheMap.putIfAbsent(arg, ft);
				if(f==null){f=ft;ft.run();}
			}
			try {
				return f.get();
			} catch (CancellationException e) {
				//如果FutureTask调用了取消那么清除缓存重新循环放入
				cacheMap.remove(arg);
			}catch (ExecutionException e) {
				e.printStackTrace();
			}
		}

	}

}


猜你喜欢

转载自chen-sai-201607223902.iteye.com/blog/2373627