Java HashMap竞争条件

Jav*_*ner 6 java multithreading synchronization race-condition

我试图找出这段代码中是否存在任何竞争条件.如果密钥不是'Thread.currentThread'那么我会认为是的.但由于线程本身是关键,如何才能有竞争条件?没有其他线程可以在HashMap中更新相同的密钥!

public class SessionTracker {

     static private final Map<Thread,Session>  threadSessionMap = new HashMap<Thread,Session>();

     static public Session get() {
         return threadSessionMap.get(Thread.currentThread());
     }

     static public void set(Session s) {
         threadSessionMap.put(Thread.currentThread(),s);
     }

     static public void reset() {
         threadSessionMap.remove(Thread.currentThread());
     }
}
Run Code Online (Sandbox Code Playgroud)

sti*_*vlo 13

答案是肯定的,有潜在的竞争条件:

  • 当两个线程同时调整 HashMap的大小
  • 碰撞发生.当两个元素映射到同一个单元格时即使它们具有不同的哈希码,也会发生冲突.在冲突解决期间,可能存在竞争条件,并且一个添加的键/值对可以被另一个线程插入的另一对覆盖.

为了更好地解释我在第二点上的意思,我在OpenJdk 7中查看了HashMap源代码

389        int hash = hash(key.hashCode());
390        int i = indexFor(hash, table.length);
Run Code Online (Sandbox Code Playgroud)

首先,它计算密钥的哈希值(组合两个哈希函数),然后映射到一个单元格indexFor,然后检查该单元格是否包含相同的密钥或已被另一个密钥占用.如果它是相同的键,它只是覆盖该值,这里没有问题.

如果它被占用,它会查看下一个单元格,然后查看下一个单元格,直到它找到一个空位置并调用addEntry(),如果数组的负载超过某个数组,它甚至可以决定调整数组的大小loadFactor.

我们table包含条目只是一个Entry包含键和值的向量.

146    /**
147     * The table, resized as necessary. Length MUST Always be a power of two.
148     */
149    transient Entry[] table;
Run Code Online (Sandbox Code Playgroud)

在并发环境中,可能发生所有类型的恶意事件,例如,一个线程获得第5个单元格的冲突并查找下一个单元格(6)并将其查找为空.

与此同时,另一个线程得到的索引为6,indexFor并且两者都决定同时使用该单元格,其中一个线程覆盖另一个.