< prev index next >
src/java.base/share/classes/java/lang/String.java
Print this page
rev 54430 : 8221836: Avoid recalculating String.hash when zero
Reviewed-by: jrose, pliden
Contributed-by: peter.levart@gmail.com, claes.redestad@oracle.com
@@ -162,10 +162,16 @@
private final byte coder;
/** Cache the hash code for the string */
private int hash; // Default to 0
+ /**
+ * Cache if the hash has been calculated as actually being zero, enabling
+ * us to avoid recalculating this.
+ */
+ private boolean hashIsZero; // Default to false;
+
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
/**
* If String compaction is disabled, the bytes in {@code value} are
@@ -1506,18 +1512,24 @@
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
+ // The hash or hashIsZero fields are subject to a benign data race,
+ // making it crucial to ensure that any observable result of the
+ // calculation in this method stays correct under any possible read of
+ // these fields. One necessary restriction to allow this to be correct
+ // without explicit memory fences or similar concurrency primitives is
+ // that we can ever only write to one of these two fields for a given
+ // String instance.
int h = hash;
- if (h == 0 && value.length > 0) {
+ if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
- // Avoid issuing a store if the calculated value is also zero:
- // in addition to a minor performance benefit, this allows storing
- // Strings with zero hash code in read-only memory.
- if (h != 0) {
+ if (h == 0) {
+ hashIsZero = true;
+ } else {
hash = h;
}
}
return h;
}
< prev index next >