package org.whf.cache;
/**
* Created by hongfei.whf on 2016/10/3.
*/
public interface Computable<INPUT, OUTPUT> {
/**
* 通过参数key得到结果value的计算过程
*
* @param input
* @return
*/
public OUTPUT compute(INPUT input) throws CalculationException;
}
package org.whf.cache.org.whf.cache.impl;
import org.whf.cache.CalculationException;
import org.whf.cache.Computable;
import java.util.concurrent.*;
/**
* Created by hongfei.whf on 2016/10/3.
*/
public class Memoizer<INPUT, OUTPUT> implements Computable<INPUT, OUTPUT> {
/**
* 缓存并发容器:
* 优势->避免访问串行化和并发造成的key的相同重复计算,以及一系列复合原子操作简化编程
*/
private final ConcurrentHashMap<INPUT, FutureTask<OUTPUT>> cache = new ConcurrentHashMap<>();
/**
* 实际进行的计算过程
*/
private Computable<INPUT, OUTPUT> calc = null;
/**
* 构造函数
*
* @param calc
*/
public Memoizer(Computable<INPUT, OUTPUT> calc) {
this.calc = calc;
}
/**
* compute 通过参数key进行一系列的计算后得到的value,并且对该结果进行缓存,
* 下次访问直接获取缓存中的结果,如果另有线程正在计算,
* 可以阻塞当前线程等待结果并且返回,避免重复计算
*
* @param input
* @return
*/
@Override
public OUTPUT compute(INPUT input) throws CalculationException {
while (true) {
FutureTask<OUTPUT> currTask = null;
if (!cache.containsKey(input) || (currTask = cache.get(input)) == null) {
FutureTask<OUTPUT> task = new FutureTask<OUTPUT>(new Callable<OUTPUT>() {
@Override
public OUTPUT call() throws Exception {
return calc.compute(input);
}
});
currTask = cache.putIfAbsent(input, task);
if (currTask == null) {
currTask = task;
currTask.run();
}
}
try {
return currTask.get();
} catch (InterruptedException e) {
cache.remove(input);
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
throw new CalculationException(e);
} catch (CancellationException e) {
cache.remove(input);
e.printStackTrace();
}
}
}
}
import org.whf.cache.CalculationException
import org.whf.cache.Computable
import org.whf.cache.org.whf.cache.impl.Memoizer
import java.io.IOException
import java.util.concurrent.Callable
import java.util.concurrent.ExecutionException
import java.util.concurrent.FutureTask
public class Main {
public static void main(String[] args) throws IOException, InterruptedException, CalculationException, ExecutionException {
Memoizer<Integer, Integer> memoizer = new Memoizer<>(new Computable<Integer, Integer>() {
@Override
public Integer compute(Integer input) {
try {
Thread.sleep(5000)
} catch (InterruptedException e) {
e.printStackTrace()
}
return input / 1
}
})
System.out.println(memoizer.compute(10))
System.out.println(memoizer.compute(10))
}
}