天天看點

java 并發程式設計中的ConcurrentModificationException 異常問題

雲渲染服務中的 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,每個段有他自己的鎖,隻要多個并發操作發生在不同的段上,就可以實作修改操作真正的并發執行