學習如何構建乙個高效且可伸縮的快取

2021-09-07 18:12:44 字數 1904 閱讀 5341

我們平時處理高併發的請求處理時,伺服器的壓力會很大。我們常做的就是構建乙個高效的可伸縮的快取來減輕伺服器的壓力。

1.第一次嘗試

分析:使用 hashmap充當cache。

public inte***ce computable

public class memoizer1implements computable

@override

public synchronized v compute(a arg) throws interruptedexception else

return result;

}}

缺點:這種方式使用synchronized來保持同步,在多個執行緒併發訪問時,會出現一些執行緒得不到memoizer1物件得鎖,它們會排隊等鎖,所以不是高效的,甚至是低效的。

2.第二次改進

分析:使用concurrenthashmap來代替hashmap

**如下:

public class memoizer2implements computable		

@override

public v compute(a arg) throws interruptedexception

return result;

}}

缺點:

3.第三次改進

分析:為了改進第二種方法中的弊端,我們可以使用future來代替concurrenthashmap中的value值。這個future 的get方法,解決了即使第一次請求花費時間較長,當第二次攜帶相同的引數請求時,不會重新再去計算,而會去等待第一次計算完成後,自己從快取中獲取。

public class memoizer3implements computable

@override

public v compute(final a arg) throws interruptedexception

};futuretaskft = new futuretask<>(callable);

f = ft;

cache.put(arg, ft);

ft.run(); //呼叫callable中的compute方法

}else

try catch (executionexception e)

return null;

}}

缺點:第三種方法實現上來說在某種意義上已經很大程度上改進了第二種方法的弊端,但是 if 裡面的操作不是原子操作,所以還是有機率會出現第二種方法的弊端。

4.第四次改進

分析:使用concurrentmap的putifabsent來代替map的put方法。

public class memoizer4implements computable

@override

public v compute(final a arg) throws interruptedexception

};futuretaskft = new futuretask<>(callable);

f = cache.putifabsent(arg, ft);

if (f == null)

}else

try catch (executionexception e)

} }}

缺點:第四種方法的實現徹底的改進了第二種方法中的弊端,但是在解決快取中的值的時間有效性還沒有解決。

java併發 構建高效且可伸縮的結果快取

幾乎所有的伺服器應用都會使用某種形式的快取。重用之前的計算結果能降低延遲,提高吞吐量,但卻要消耗更多記憶體。看上去簡單的快取,可能會將效能瓶頸轉變成伸縮性瓶頸,即使快取是用來提高單執行緒效能的。本文將開發乙個高效且可伸縮的快取,用於改進乙個高計算開銷的計算,我們會從hashmap開始,逐步完善功能,...

java併發程式設計實戰 構建高效且可伸縮的結果快取

構建高效且可伸縮的結果快取 1,快取在伺服器應用程式中是乙個非常重要的元件。2,以下講解乙個高效且可伸縮的快取示例 如下 public class cachesample futuretaskft new futuretask eval 通過putifabsent完成 先檢查再新增 的原子操作 pu...

構建高效且可伸縮的結果快取引申的併發測試規範化

有些東西其實就是一層紙,當你偶然穿透的時候,就會豁然開朗,眼前一亮。以前總是對一些併發測試不感冒,有時候覺得我從下手的感覺。但是不自己親自測試一把又覺得不放心,於是總是在thread裡面來來回回的修改,在run方法中做這個中修改,總是亂亂的感覺。今天突然從別人的 中頓悟了,體系終於明朗了。我以構建高...