雲渲染服務中的 java.util.ConcurrentModificationException 異常問題
針對最近雲渲染服務中的出現的一個問題進行反思與回顧
回調視訊渲染進度問題
-
在修改過回調進度的 url 後,啟用了之前的代碼片段。導緻之前的漏洞被爆出:在多線程程式設計中,直接使用 hashmap 來儲存目前的渲染任務,而不進行一些必要的線程間的互斥與同步操作,導緻在一個線程通過疊代器周遊 hashmap 時,另一個線程同時修改 hashmap,導緻程式抛出
java.util.ConcurrentModificationException 異常
程式後續也沒有處理該異常,導緻任務不斷失敗java.util.ConcurrentModificationException at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493) at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1516) at com.seeshion.schedule.ProcessTask.test(ProcessTask.java:39) at jdk.internal.reflect.GeneratedMethodAccessor32.invoke(Unknown Source) ...
解決辦法
-
HashTable
可以使用 HashTable 來解決該問題,HashTable<K, V> 也是一種鍵值對結構的哈希表,和 HashMap 的操作大體一緻,但不同的是:HashMap 不是線程安全的類,多線程環境下,HashMap 會出現并發沖突。而 HashTable 是線程安全的類,為了實作多線程安全,HashTable 使用 synchronized 鎖住整張 Hash 表 即每次鎖住整張表實作線程安,HashTable 幾乎在所有的方法上都加了鎖,但也導緻了操作效率低下。在雲渲染服務場景中,這點時間可以忽略不計。
-
ConcurrentHashMap
ConcurrentHashMap 是比 HashTable 效率更高的并發容器,使用了鎖分離技術,即使用多個鎖來鎖住 Hash 表的不同部分,這些不同的部分成為 segment 段,每個段其實就是一個一個的 HashTable,每個段有他自己的鎖,隻要多個并發操作發生在不同的段上,就可以實作修改操作真正的并發執行