Java结果缓存实现(Thread Safe)

使用FutureTask实现:

import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class Cache {
	private final ConcurrentHashMap> cache
			= new ConcurrentHashMap>();
	
	public Long getSquare(final Long arg) throws 
			InterruptedException{
		for(;;){
			Future f = cache.get(arg);
			if(f == null){
				System.out.println("null");
				//请求参数没有命中缓存
				//如果同一时间有多个针对该参数的请求到达
				//则会创建多个针对同一个请求参数的FutureTask对象
				FutureTask ft = new FutureTask(
					new Callable(){
						public Long call() throws Exception {
							System.out.println("called");
							long l = arg.longValue();
							l = l * l;
							return Long.valueOf(l);
						}
					}
				);
				//如果map中没有相应的key,则入map并返回null
				//否则返回map中相应key的value值
				//该方法是线程安全的
				//因此即使有多个请求参数相同的请求同时到达
				//只有一个请求处理过程中创建的FutureTask对象被加入缓存
				//剩余请求从缓存中获取之前加入的FutureTask对象
				System.out.println(ft.hashCode());
				f = cache.putIfAbsent(arg, ft);
				//插入FutureTask的线程同时启动该FutureTask
				if(f == null){
					f = ft;
					ft.run();
				}
			}
			try {
				return f.get();
			} catch (CancellationException e) {
				//如果FutureTask由于某些原因而被取消
				//则需从缓存中移除
				//以便将新的FutureTask加入缓存
				cache.remove(arg);
			} catch (ExecutionException e) {
				this.dealException(e.getCause());
			}
		}
	}
	
	private void dealException(Throwable e){
		if(e instanceof Error)
			throw (Error)e;
		else if(e instanceof RuntimeException)
			throw (RuntimeException)e;
		else
			throw (IllegalStateException)e;
	}
}
import java.util.concurrent.CountDownLatch;

public class Test implements Runnable {
	private Cache cache;
	private final static CountDownLatch latch
			= new CountDownLatch(1);
	
	public Test(Cache cache){
		this.cache = cache;
	}
	
	@Override
	public void run() {
		try {
			latch.await();
			long result = cache.getSquare(Long.valueOf((long)123));
			System.out.println(
					Thread.currentThread().getName() + 
					":" + result
					);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		Cache cache = new Cache();
		for(int i = 0 ; i < 10 ; i++){
			new Thread(new Test(cache),"Thread-" + i).start();
		}
		//10个线程同时运行
		latch.countDown();
	}
}

运行结果如下:

10个线程是同时运行的,故10个线程在初始判断时都没有命中缓存

因而创建了10个FutureTask对象,但是只有一个被加入缓存

null
null
null
null
null
null
null
null
null
null
444956
8795033
3043939
22540508
12717604
1280484
19581314
29303146
29303146
444956
called
Thread-0:15129
Thread-9:15129
Thread-6:15129
Thread-7:15129
Thread-8:15129
Thread-5:15129
Thread-1:15129
Thread-4:15129
Thread-3:15129
Thread-2:15129

 

你可能感兴趣的:(Java,Multithreading)