我想對資料訪問做一個緩衝,選用Map來做緩衝容器,考慮到效率我選擇了HashMap
想想迴圈往裡面仍或者更新資料,那麼當系統不訪問的時候這些內容,我應該即時的清除這些記憶體內容
根據需要,我寫了一個靜態Map做記憶體容器,然後設定一個Spring定時器來定時檢查和處理那些資料需要清除
但是定時器處理時遇到異常 java.util.ConcurrentModificationException ,遇到安全執行緒問題
查了一下HashMap的API介紹:
注意,此實現不是同步的。如果多個線程同時訪問一個雜湊映射,而其中至少一個線程從結構上修改了該映射,則它必須 保持外部同步。(結構上的修改是指添加或刪除一個或多個映射關係的任何操作;僅改變與執行個體已經包含的鍵關聯的值不是結構上的修改。)這一般通過對自然封裝該映射的對象進行同步操作來完成。如果不存在這樣的對象,則應該使用 Collections.synchronizedMap 方法來“封裝”該映射。最好在建立時完成這一操作,以防止對映射進行意外的非同步訪問,如下所示:
Map m = Collections.synchronizedMap(new HashMap(...));
由所有此類的“collection 視圖方法”所返回的迭代器都是快速失敗 的:在迭代器建立之後,如果從結構上對映射進行修改,除非通過迭代器本身的 remove 方法,其他任何時間任何方式的修改,迭代器都將拋出ConcurrentModificationException。因此,面對並發的修改,迭代器很快就會完全失敗,而不冒在將來不確定的時間發生任意不確定行為的風險。
注意,迭代器的快速失敗行為不能得到保證,一般來說,存在非同步的並發修改時,不可能作出任何堅決的保證。快速失敗迭代器盡最大努力拋出 ConcurrentModificationException。因此,編寫依賴於此異常的程式的做法是錯誤的,正確做法是:迭代器的快速失敗行為應該僅用於檢測程式錯誤。
怎麼解決呢。
找了一下API,在1.5後有這樣一個Map對象ConcurrentHashMap
介紹如下:
支援擷取的完全並發和更新的所期望可調整並發的雜湊表。此類遵守與 Hashtable 相同的功能規格,並且包括對應於 Hashtable 的每個方法的方法版本。不過,儘管所有操作都是安全執行緒的,但擷取操作不 必鎖定,並且不 支援以某種防止所有訪問的方式鎖定整個表。此類可以通過程式完全與 Hashtable 進行互操作,這取決於其安全執行緒,而與其同步細節無關。
擷取操作(包括 get)通常不會受阻塞,因此,可能與更新操作交迭(包括 put 和 remove)。擷取會影響最近完成的 更新操作的結果。對於一些彙總操作,比如 putAll 和 clear,並發擷取可能隻影響某些條目的插入和移除。類似地,在建立迭代器/枚舉時或自此之後,Iterators 和 Enumerations 返回在某一時間點上影響雜湊表狀態的元素。它們不會 拋出 ConcurrentModificationException。不過,迭代器被設計成每次僅由一個線程使用。
這允許通過可選的 concurrencyLevel 構造方法參數(預設值為 16)來引導更新操作之間的並發,該參數用作內部調整大小的一個提示。表是在內部進行分區的,試圖允許指示無爭用並發更新的數量。因為雜湊表中的位置基本上是隨意的,所以實際的並發將各不相同。理想情況下,應該選擇一個儘可能多地容納並發修改該表的線程的值。使用一個比所需要的值高很多的值可能會浪費空間和時間,而使用一個顯然低很多的值可能導致線程爭用。對數量級估計過高或估計過低通常都會帶來非常顯著的影響。當僅有一個線程將執行修改操作,而其他所有線程都只是執行讀取操作時,才認為某個值是合適的。此外,重新調整此類或其他任何種類雜湊表的大小都是一個相對較慢的操作,因此,在可能的時候,提供構造方法中期望表大小的估計值是一個好主意。
此類及其視圖和迭代器實現了 Map 和 Iterator 介面的所有可選 方法。
此類與 Hashtable 相似,但與 HashMap 不同,它不 允許將 null 用作鍵或值。
這兩個對象的載入因子都是0.75,因此可以考慮進行替換。
緩衝類: Java代碼 /** * @說明 將監控擷取的網路值進行記憶體緩衝 * @author cuisuqiang * @version 1.0 * @since */ public class JianKongMapKeep { /** * 使用安全執行緒的Map對象 */ public static Map<String,JianKongKeep> keepMaps = new ConcurrentHashMap<String,JianKongKeep>(); /** * 獲得某值 * @param key * @return */ public static JianKongKeep getKeepListByKey(String key){ JianKongKeep jianKongKeep = new JianKongKeep(); jianKongKeep = keepMaps.get(key); return jianKongKeep; } /** * 新增或更新 * @param key * @param jianKongKeep */ public static void saveOrUpdateJianKongKeep(String key,JianKongKeep jianKongKeep){ keepMaps.put(key, jianKongKeep); } }
定時器執行類: Java代碼 /** * @說明 定時清理監控的記憶體內容 * @author cuisuqiang * @version 1.0 * @since */ public class JianKongMapKeepTimer { public void checkJianKongKeep(){ try {