posts - 9, comments - 4, trackbacks - 0, articles - 21
          有一個很耗時的運算需要緩存其計算結果,采用備忘錄模式實現,如:
          Java代碼 
          1. public interface Computable<A, V> {  
          2.     V compute(A arg) throws InterruptedException;  
          3. }  
          4.   
          5. public class ExpensiveFunction  
          6.         implements Computable<String, BigInteger> {  
          7.     public BigInteger compute(String arg) {  
          8.         // 假設這里非常耗時...  
          9.         return new BigInteger(arg);  
          10.     }  
          11. }  


          備忘錄緩存方案一:
          Java代碼 
          1. public class Memoizer1<A, V> implements Computable<A, V> {  
          2.     @GuardedBy("this")  
          3.     private final Map<A, V> cache = new HashMap<A, V>();  
          4.     private final Computable<A, V> c;  
          5.   
          6.     public Memoizer1(Computable<A, V> c) {  
          7.         this.c = c;  
          8.     }  
          9.   
          10.     public synchronized V compute(A arg) throws InterruptedException {  
          11.         V result = cache.get(arg);  
          12.         if (result == null) {  
          13.             result = c.compute(arg);  
          14.             cache.put(arg, result);  
          15.         }  
          16.         return result;  
          17.     }  
          18. }  

          這里備忘錄的整個compute過程被同步,相當于我最原始的低效方案,


          備忘錄緩存方案二:
          Java代碼 
          1. public class Memoizer2<A, V> implements Computable<A, V> {  
          2.     private final Map<A, V> cache = new ConcurrentHashMap<A, V>();  
          3.     private final Computable<A, V> c;  
          4.   
          5.     public Memoizer2(Computable<A, V> c) { this.c = c; }  
          6.   
          7.     public V compute(A arg) throws InterruptedException {  
          8.         V result = cache.get(arg);  
          9.         if (result == null) {  
          10.             result = c.compute(arg);  
          11.             cache.put(arg, result);  
          12.         }  
          13.         return result;  
          14.     }  
          15. }  

          將線程安全性委給cache,注:這個方案的cache用了ConcurrentHashMap,它是線程安全的。

          備忘錄緩存方案三:
          Java代碼 
          1. public class Memoizer3<A, V> implements Computable<A, V> {  
          2.     private final Map<A, Future<V>> cache  
          3.             = new ConcurrentHashMap<A, Future<V>>();  
          4.     private final Computable<A, V> c;  
          5.   
          6.     public Memoizer3(Computable<A, V> c) { this.c = c; }  
          7.   
          8.     public V compute(final A arg) throws InterruptedException {  
          9.         Future<V> f = cache.get(arg);  
          10.         if (f == null) {  
          11.             Callable<V> eval = new Callable<V>() {  
          12.                 public V call() throws InterruptedException {  
          13.                     return c.compute(arg);  
          14.                 }  
          15.             };  
          16.             FutureTask<V> ft = new FutureTask<V>(eval);  
          17.             f = ft;  
          18.             cache.put(arg, ft);  
          19.             ft.run(); // call to c.compute happens here  
          20.         }  
          21.         try {  
          22.             return f.get();  
          23.         } catch (ExecutionException e) {  
          24.             throw launderThrowable(e.getCause());  
          25.         }  
          26.     }  
          27. }  

          使用Future(相當上一帖的Entry)封裝,因為這里資源獲取過程不固定(通用方案),所以使用了Callable進行回調資源獲取過程(求值),
          這個方案的 if (f == null) 不安全,特殊性可能會進行多次運算,下面的方案四解決這個問題。

          備忘錄緩存方案四(最終方案):
          Java代碼 
          1. public class Memoizer<A, V> implements Computable<A, V> {  
          2.     private final ConcurrentMap<A, Future<V>> cache  
          3.         = new ConcurrentHashMap<A, Future<V>>();  
          4.     private final Computable<A, V> c;  
          5.   
          6.     public Memoizer(Computable<A, V> c) { this.c = c; }  
          7.   
          8.     public V compute(final A arg) throws InterruptedException {  
          9.         while (true) {  
          10.             Future<V> f = cache.get(arg);  
          11.             if (f == null) {  
          12.                 Callable<V> eval = new Callable<V>() {  
          13.                     public V call() throws InterruptedException {  
          14.                         return c.compute(arg);  
          15.                     }  
          16.                 };  
          17.                 FutureTask<V> ft = new FutureTask<V>(eval);  
          18.                 f = cache.putIfAbsent(arg, ft);  
          19.                 if (f == null) { f = ft; ft.run(); }  
          20.             }  
          21.             try {  
          22.                 return f.get();  
          23.             } catch (CancellationException e) {  
          24.                 cache.remove(arg, f);  
          25.             } catch (ExecutionException e) {  
          26.                 throw launderThrowable(e.getCause());  
          27.             }  
          28.         }  
          29.     }  

          主站蜘蛛池模板: 平南县| 榆社县| 宿松县| 哈密市| 邵东县| 宁安市| 谢通门县| 徐州市| 上饶市| 潮安县| 甘德县| 昌黎县| 长阳| 永和县| 芮城县| 哈密市| 固始县| 三明市| 米脂县| 桐梓县| 罗源县| 伊通| 定安县| 方正县| 泾阳县| 泰州市| 那曲县| 蚌埠市| 丹棱县| 镶黄旗| 五莲县| 威信县| 兴城市| 苍山县| 永顺县| 石屏县| 布拖县| 阳山县| 乐昌市| 中方县| 惠东县|