Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.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.get(key)?_Java_Multithreading_Synchronization - Fatal编程技术网

Java 为什么在同步更改操作时需要同步HashMap.get(key)?

Java 为什么在同步更改操作时需要同步HashMap.get(key)?,java,multithreading,synchronization,Java,Multithreading,Synchronization,我在一个HashMap上使用来自多个线程的.get(…)、.put(…)和.clear()操作.put(…)和.clear()在已同步的块中,但.get(…)不是。我无法想象这会导致问题,但在我看到的其他代码中,.get()几乎总是同步的 get/put的相关代码 Object value = map.get(key); if(value == null) { synchronized (map) { value = map.get(key); // check again, mig

我在一个HashMap上使用来自多个线程的
.get(…)
.put(…)
.clear()
操作
.put(…)
.clear()
已同步的
块中,但
.get(…)
不是。我无法想象这会导致问题,但在我看到的其他代码中,
.get()
几乎总是同步的

get/put的相关代码

Object value = map.get(key);
if(value == null) {
  synchronized (map) {
    value = map.get(key); // check again, might have been changed in between
    if(value == null) {
      map.put(key, new Value(...));
    }
  }
}
清楚的是:

synchronized (map) {
  map.clear();
}

写入操作将使缓存无效,因为同步操作和
get(…)
返回null或实例。通过将
.get(…)
操作放入
synchronized(map)
块中,我真的看不出会出现什么问题或会有什么改进。

下面是一个简单的场景,它会在非同步
get
时产生问题:

  • 线程A启动
    get
    ,计算散列存储桶编号,并被抢占
  • 线程B调用
    clear()
    ,因此会分配一个较小的存储桶数组
  • 线程A唤醒,可能会遇到索引越界异常
下面是一个更复杂的场景:

  • 线程A锁定地图进行更新,并被抢占
  • 线程B启动一个
    get
    操作,计算散列存储桶编号,并被抢占
  • 线程A醒来,继续执行
    放置
    ,并意识到存储桶需要调整大小
  • 线程A分配新的存储桶,将旧内容复制到存储桶中,并添加新项
  • 线程B唤醒,并使用新存储桶数组上的旧存储桶索引继续搜索

此时,A可能无法找到正确的项,因为它很可能位于不同索引的哈希桶中。这就是为什么
get
也需要同步的原因。

上述所有操作都可以在程序的顺序一致执行中发生,但Java甚至不能保证SC。因此,即使要以某种方式避免这里描述的所有问题,
get
仍需同步。这就是创建java.util.concurrent.locks.ReadWriteLock的原因。