Reputation: 127
Java Concurrency In Practice by Brian Goetz provides an example of a efficient scalable cache for concurrent use. Here is the code for the class:
public class Memoizer<A, V> implements Computable<A, V> {
private final ConcurrentMap<A, Future<V>> cache
= new ConcurrentHashMap<A, Future<V>>();
private final Computable<A, V> c;
public Memoizer(Computable<A, V> c) { this.c = c; }
public V compute(final A arg) throws InterruptedException {
while (true) {
Future<V> f = cache.get(arg);
if (f == null) {
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
f = cache.putIfAbsent(arg, ft);
if (f == null) { f = ft; ft.run(); }
}
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);
} catch (ExecutionException e) {
throw launderThrowable(e.getCause());
}
}
} }
Probably a stupid question but coudl anyone show me the concurrent usage of this class? Like in a main?
Cheers, Agata
Upvotes: 7
Views: 3228
Reputation: 274612
Here is an example which calculates factorials:
public static void main(String[] args) throws Exception {
//create a memoizer that performs factorials
final Memoizer<Integer, Integer> memo = new Memoizer<Integer, Integer> (new Computable<Integer, Integer>() {
@Override
public Integer compute(Integer a) {
int result = 1 ;
for(int i = 1 ; i < a ; i++){
result = result*i;
}
return result;
}
});
//now call the memoizer
System.out.println(memo.compute(10));
//call it with 10 threads concurrently
ExecutorService exec = Executors.newFixedThreadPool(10);
ExecutorCompletionService<Integer> compService = new ExecutorCompletionService<Integer>(exec);
for(int i = 0 ; i < 15 ; i++){
compService.submit(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
return memo.compute(5);
}
});
}
exec.shutdown();
for(int i = 0 ; i < 15 ; i++){
System.out.println(compService.take().get());
}
}
So if two threads try to compute the same factorial at exactly the same time, only one of them will actually perform the computation, because putIfAbsent
is threadsafe. The second thread will simply get the future which was put in the map by the first thread and wait for it to finish.
Upvotes: 6
Reputation: 116266
I could imagine something like this:
class PrimeDetector implements Computable<BigInteger, Boolean> {
public Boolean compute(BigInteger number) {
// detect whether the number is prime and return true if it is
}
}
Memoizer<BigInteger, Boolean> primeMemoizer =
new Memoizer<BigInteger, BigInteger[]>(new PrimeDetector());
boolean isPrime = primeMemoizer.compute(
new BigInteger("5625945193217348954671586615478165774647538956473535"));
...
Upvotes: 1