安全地迭代由多个线程访问的ConcurrentHashMap

时间:2014-09-28 19:47:47

标签: java multithreading

我有一个ConcurrentHashMap对象,由多个线程共享来访问:

Map<String, MyConnection> myMap = new ConcurrentHashMap<String, MyConnection>();

MyConnection类包含与数据源的一些连接。

稍后,我需要迭代ConcurrentHashMap,调用MyConnection.close()方法并将其从Map中删除。像这样:

for(String key : myMap.ketSet()) {
    MyConnection connection = myMap.get(key);
    connection.close();
    myMap.remove(key);
}

但是,myMap由多个线程共享,可以添加,同时从ConcurrentHashMap中删除。

如何确保上面的for循环是否可以运行?不要求循环必须删除映射中的所有条目。循环只需要在调用myMap.keySet()时删除所有元素。不必删除添加到地图中的任何后续元素。

显然我可以锁定整个for循环并防止其他线程触及地图,但我认为它不具备性能效率。

有人可以分享您的意见吗?

EDIT1 :这个怎么样?这个线程安全吗?

for(MyConnection connection : myMap.values()) {
    connection.close();
    myMap.remove(connection.getId());
}

每个连接对象都有一个ID,它也是该条目的关键字。

3 个答案:

答案 0 :(得分:0)

您的方法目前不安全,因为您的connection可能是null(如果另一个线程在您进行迭代时将其删除),则可能会抛出NullPointerException。只需添加一个空检查,您的方法是正确的,并且是线程安全的。

如果你关注性能,你可能想简单地迭代map.values()并以这种方式删除变量,每次迭代可以节省两次地图查找:

//the following code has not been compiled, and may be incorrect
Iterator<MyConnection> it = myMap.values().iterator();
while(it.hasNext())
{
    MyConnection c = it.next();
    c.close();
    it.remove();
}

答案 1 :(得分:0)

迭代/循环你呈现的方式不是线程安全的,因为你没有迭代最新的地图。但这不是你的问题,因为你只是从hashmap中删除一个元素 - 并且IS线程安全(由于ConcurrentHashMap)。无需锁定或同步它没有任何意义。

你的两次迭代都没问题,因为你只删除了它并写了:

  

循环只需要删除当时的所有元素   myMap.keySet()被调用。

你的代码很好。在关闭之前,您可能需要检查连接是否为空(如建议的那样)

答案 2 :(得分:0)

正确的方法是使用remove的返回值:

for(String key : myMap.ketSet()) {
    MyConnection connection = myMap.remove(key);
    if (connection != null)
        connection.close();
}