記一次fastjson多線程異常

背景:

在一次生產環境日誌分析中看到了一條異常信息:

java.util.ConcurrentModificationException: null
at java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1211) ~[na:1.8.0_181]
at java.util.TreeMap$KeyIterator.next(TreeMap.java:1265) ~[na:1.8.0_181]
at com.alibaba.fastjson.serializer.CollectionCodec.write(CollectionCodec.java:68) ~[fastjson-1.2.30.jar:na]
at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:304) ~[fastjson-1.2.30.jar:na]
at com.alibaba.fastjson.serializer.ASMSerializer_22_LearnMapCounter.write(Unknown Source) ~[na:na]
at com.alibaba.fastjson.serializer.ASMSerializer_18_CacheSession.write(Unknown Source) ~[na:na]
at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:275) ~[fastjson-1.2.30.jar:na]
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:648) ~[fastjson-1.2.30.jar:na]
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:590) ~[fastjson-1.2.30.jar:na]
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:555) ~[fastjson-1.2.30.jar:na]

多線程修改異常;

追根溯源,發現該異常出現在使用kafka消費者進行消息發送的時候出現的,我們的發送方法,是採用了Spring 的 @Asyc註解進行異步發送的,由於kafka生產者默認使用了字符串類型的序列化方式,所以我們需要把需要發送的對象的對象利用fastjson轉換成json字符串,於是出現瞭如上異常!

分析思路:

通常我們在遍歷集合的時候對集合進行刪除的時候是會出現多線程修改異常的也就是如上ConcurrentModificationException,原因是因爲Java對集合的遍歷是利用迭代器進行實現的,而迭代器的實現原理就是在每次迭代的時候會對目標對象進行標記,如果發現對象被修改則會拋出多線程修改異常,因此在《阿里巴巴的開發規範》中也明確表示:“【強制】在 subList 場景中,高度注意對原集合元素的增加或刪除,均會導致子列表的遍歷、 增加、刪除產生ConcurrentModificationException 異常。”  聯繫到我們的業務場景,每次生產者通過形參傳入新的消息進行發送,那麼此時形參已經盡心修改,而此時fastjson還在對對象進行處理,所以拋出如上異常。

解決辦法:

每次發送對象的時候,進行對象拷貝,把拷貝對象進行fastjson的序列化操作,因此避免直接對形參傳入對象操作;

利用Spring框架提供的BeanUtils方法對對象進行拷貝,發送完畢後釋放拷貝對象內存;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章