作者:张伟
关于HashMap在并发场景下的问题有很多人,很多公司遇到过!也很多人总结过,我们很多时候都认为这样的坑距离自己很远,自己一定不会掉入这样的坑。可是我们随时都有就遇到了这样的问题,坑一直都在我们身边。今天遇到了一个非线程安全对象在并发场景下使用的问题,通过这个案例分析HashMap 在并发场景下使用存在的问题(当然在这个案例中还有很多问题值得我们去分析,值得大家引以为戒。)通过分析问题产生的原因,让我们今后更好远离这个BUG。
Doug Lea writes:
"This is a classic symptom of an incorrectly synchronized use of
HashMap. Clearly, the submitters need to use a thread-safe
HashMap. If they upgraded to Java 5, they could just use
ConcurrentHashMap. If they can't do this yet, they can use
either the pre-JSR166 version, or better, the unofficial backport
as mentioned by Martin. If they can't do any of these, they can
use Hashtable or synchhronizedMap wrappers, and live with poorer
performance. In any case, it's not a JDK or JVM bug."
I agree that the presence of a corrupted data structure alone
does not indicate a bug in the JDK.
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);
}
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
下面是线程栈的部分日志:
DubboServerHandler-10.172.75.33:20880-thread-139" daemon prio=10 tid=0x0000000004a93000 nid=0x76fe runnable [0x00007f0ddaf2d000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.getEntry(HashMap.java:465)
at java.util.HashMap.containsKey(HashMap.java:449)
"pool-9-thread-16" prio=10 tid=0x00000000033ef000 nid=0x4897 runnable [0x00007f0dd62cb000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.put(HashMap.java:494)
DubboServerHandler-10.172.75.33:20880-thread-189" daemon prio=10 tid=0x00007f0de99df800 nid=0x7722 runnable [0x00007f0dd8b09000]
java.lang.Thread.State: RUNNABLE
at java.lang.Thread.yield(Native Method)
DubboServerHandler-10.172.75.33:20880-thread-157" daemon prio=10 tid=0x00007f0de9a94800 nid=0x7705 runnable [0x00007f0dda826000]
java.lang.Thread.State: RUNNABLE
at java.lang.Thread.yield(Native Method)
网易云大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者张伟授权发布