【问题标题】:java String hashcode caching mechanismjava String hashcode缓存机制
【发布时间】:2017-04-27 09:18:35
【问题描述】:

查看 Java 的 String 类,我们可以看到哈希码在第一次评估后被缓存。

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

其中hash 是一个实例变量。我有一个问题,为什么我们需要那个 h 额外变量?

【问题讨论】:

  • 这样写是为了保证String类是线程安全的。你可以阅读更多关于这个概念here
  • 那个维基百科链接没有完全解释这里发生了什么或为什么。

标签: java hashcode


【解决方案1】:

仅仅是因为hash 值在循环中发生了变化,并且没有中间临时变量的解决方案不是线程安全的。考虑在多个线程中调用此方法。

thread-1 开始hash 计算,它不再是0。稍后thread-2 在同一个对象上调用相同的方法hashCode() 并看到hash 不是0,但thread-1 还没有完成它的计算。结果,在thread-2 错误的hash(未完全计算)值将被使用。

【讨论】:

    【解决方案2】:

    这是一种简单而廉价的同步机制。

    如果一个线程第一次调用 hashCode() 并且第二个线程在第一个线程计算散列时再次调用它,第二个线程将返回一个不正确的散列(第一个线程中计算的中间值)如果直接使用属性。

    【讨论】:

    • 注意这里的线程安全并不能阻止多个线程计算hash。因为没有同步机制,所以不能保证 a) 两个线程不会访问 hash 而它仍然是 0,也不能保证 b) 即使在一个线程进行缓存之后,任何其他线程都会看到结果。为什么它是线程安全的,尽管可能被计算了很多次?因为计算是幂等的;没有两个线程可以计算不同的值。
    • 完全正确,卢。在这种情况下,与在字符串的生命周期内不需要任何同步机制的好处相比,在开始时计算两次哈希的影响较小。
    【解决方案3】:

    说的很简单:局部原语h很好local;因此是线程安全的;而hash 是共享的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-01
      • 2017-08-12
      • 1970-01-01
      • 2015-01-08
      • 1970-01-01
      • 2016-10-14
      相关资源
      最近更新 更多