Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 这个HashMap使用线程安全吗?_Java_Multithreading - Fatal编程技术网

Java 这个HashMap使用线程安全吗?

Java 这个HashMap使用线程安全吗?,java,multithreading,Java,Multithreading,我有一个静态HashMap,它将缓存由唯一整数标识的对象;它将从多个线程访问。我将在不同的线程中运行多个类型为HashmapUser的实例,每个实例都希望使用相同的HashMap(这就是为什么它是静态的) 通常,HashmapUsers将从HashMap中检索。但是如果它是空的,则需要从数据库填充它。此外,在某些情况下,HashMap将被清除,因为它需要数据发生更改并且需要重新填充 所以,我只是将所有与地图的交互同步。但我不能肯定这是安全的,聪明的,或者它对静态变量有效 下面这个线程的实现是安全

我有一个静态HashMap,它将缓存由唯一整数标识的对象;它将从多个线程访问。我将在不同的线程中运行多个类型为
HashmapUser
的实例,每个实例都希望使用相同的HashMap(这就是为什么它是静态的)

通常,
HashmapUsers
将从HashMap中检索。但是如果它是空的,则需要从数据库填充它。此外,在某些情况下,HashMap将被清除,因为它需要数据发生更改并且需要重新填充

所以,我只是将所有与地图的交互同步。但我不能肯定这是安全的,聪明的,或者它对静态变量有效

下面这个线程的实现是安全的吗?有没有简化或改进的建议

public class HashmapUser {

  private static HashMap<Integer, AType> theMap = new HashSet<>();

  public HashmapUser() {
    //....
  }

  public void performTask(boolean needsRefresh, Integer id) {
    //....

    AType x = getAtype(needsRefresh, id);

    //....
  }

  private synchronized AType getAtype(boolean needsRefresh, Integer id) {
    if (needsRefresh) {
      theMap.clear();
    }

    if (theMap.size() == 0) {
      // populate the set
    }

    return theMap.get(id);
  }
}
公共类HashmapUser{
私有静态HashMap theMap=newhashset();
公共HashmapUser(){
//....
}
public void performTask(布尔需要刷新,整数id){
//....
AType x=getAtype(需要刷新,id);
//....
}
私有同步AType getAtype(布尔需要刷新,整数id){
如果(需要刷新){
theMap.clear();
}
如果(theMap.size()=0){
//填充集合
}
返回map.get(id);
}
}

我建议您选择
ConcurrentHashMap
SynchronizedMap
。 更多信息请点击此处:

ConcurrentHashMap
更适合高并发性场景。此实现不会对整个对象进行同步,而是以优化的方式进行同步,因此访问不同密钥的不同线程可以同时进行同步

SynchronizerMap
更简单,在对象级别执行同步-对实例的访问是串行的


我认为您需要性能,因此我认为您可能应该选择
ConcurrentHashMap

我建议您选择
ConcurrentHashMap
SynchronizedMap
。 更多信息请点击此处:

ConcurrentHashMap
更适合高并发性场景。此实现不会对整个对象进行同步,而是以优化的方式进行同步,因此访问不同密钥的不同线程可以同时进行同步

SynchronizerMap
更简单,在对象级别执行同步-对实例的访问是串行的


我认为您需要性能,因此我认为您可能应该使用
ConcurrentHashMap

,因为它绝对不是线程安全的。
HashmapUsers
的每个实例将使用不同的锁(
this
),这没有任何用处。您必须在同一对象上进行同步,例如HashMap本身

getAtype
更改为:

private AType getAtype(boolean needsRefresh, Integer id) {
    synchronized(theMap) {
        if (needsRefresh) {
          theMap.clear();
        }

        if (theMap.size() == 0) {
          // populate the set
        }

        return theMap.get(id);
    }
  }
编辑: 请注意,如果所有实例都使用同一对象进行同步,则可以在任何对象上进行同步。您可以在
HashmapUsers.class
上进行同步,这也允许其他对象锁定对映射的访问(尽管使用私有锁通常是最佳做法)


因此,只需将
getAtype
方法设为静态即可,因为隐含的锁现在是
HashMapUsers.class
而不是
this
。但是,这会暴露您的锁,这可能是您想要的,也可能不是您想要的。

事实上,它绝对不是线程安全的。
HashmapUsers
的每个实例将使用不同的锁(
this
),这没有任何用处。您必须在同一对象上进行同步,例如HashMap本身

getAtype
更改为:

private AType getAtype(boolean needsRefresh, Integer id) {
    synchronized(theMap) {
        if (needsRefresh) {
          theMap.clear();
        }

        if (theMap.size() == 0) {
          // populate the set
        }

        return theMap.get(id);
    }
  }
编辑: 请注意,如果所有实例都使用同一对象进行同步,则可以在任何对象上进行同步。您可以在
HashmapUsers.class
上进行同步,这也允许其他对象锁定对映射的访问(尽管使用私有锁通常是最佳做法)


因此,只需将
getAtype
方法设为静态即可,因为隐含的锁现在是
HashMapUsers.class
而不是
this
。但是,这会暴露您的锁,这可能是您想要的,也可能不是您想要的。

不,这根本不起作用

如果不指定锁对象,例如declare方法
synchronized
,则隐式锁将是实例。除非方法是静态的,否则锁将是类。因为有多个实例,所以也有多个锁,我怀疑这是需要的

您应该做的是创建另一个类,它是唯一可以访问
HashMap
的类

HashMap
的客户端,例如
HashMapUser
甚至不能意识到存在同步。相反,应该通过适当的类包装
HashMap
来确保线程安全,从而对客户端隐藏同步


这使您可以轻松地将其他客户端添加到
HashMap
,因为同步对它们是隐藏的,否则您也必须在不同的客户端类型之间添加某种类型的同步。

不,这根本不起作用

如果不指定锁对象,例如declare方法
synchronized
,则隐式锁将是实例。除非方法是静态的,否则锁将是类。因为有多个实例,所以也有多个锁,我怀疑这是需要的

您应该做的是创建另一个类,它是唯一可以访问
HashMap
的类

HashMap
的客户端,例如
HashMapUser
甚至不能意识到存在同步。相反,应该通过适当的类包装
HashMap
来确保线程安全,从而对客户端隐藏同步

这使您可以轻松地将其他客户端添加到