fastjson IdentityHashMap is NOT threadsafe

h9a6wy2h  于 2022-10-22  发布在  其他
关注(0)|答案(6)|浏览(136)

IdentityHashMap的put不是线程安全的, 里面的注解也写着"// 并发是处理时会可能导致缓存丢失,但不影响正确性".
也就是put后不能保证一定能写上, 但SerializeConfig.getObjectWriter里有很多对IdentityHashMap的put然后get相同key的操作, 并发会导致get可能得不到刚刚put的结果, 导致可能返回null而触发空指针异常!
触发异常的位置是: ObjectFieldSerializer.writeValue里的runtimeInfo.fieldSerializer.write, fieldSerializer实际可能是null.

bpsygsoo

bpsygsoo1#

能做个testcase复现问题吗

w6mmgewl

w6mmgewl2#

我觉得这已经是很明显的bug, 虽然复现难度非常大.
但有亿万分之一的概率出错的可能, 作为一个广泛推广的开源库难道也是不该考虑的么?

Entry<K, V> entry = new Entry<K, V>(key, value, hash, buckets[bucket]);
        buckets[bucket] = entry;  // 并发是处理时会可能导致缓存丢失,但不影响正确性

另外像这种写法, 由于没有voletile或其它保护, 乱序执行会导致先执行下面那行赋值,后执行entry.next的赋值也是可能的(包括cpu cache在不同核心的同步问题),更容易导致get不到.

k10s72fa

k10s72fa3#

我觉得这里就老老实实用ConcurrentHashMap就可以了, Class类的equals并没有重写, 用IdentityHashMap也没什么好处.

gv8xihay

gv8xihay4#

安全的,这里没问题,得不到重新Put一次不影响后续使用哈。

laximzn5

laximzn55#

如果缓存拿不到就会直接重新new一个,只是会变慢一点。

6mw9ycah

6mw9ycah6#

重新new是没问题, 但关键是new的对象就put到map里, 然后后面不是返回这个new的对象, 而是又从map中get了一次,然后就没有判空了(见SerializeConfig.java的getObjectWriter(Class<?> clazz, boolean create)函数的最后几行)

相关问题