< prev index next >
src/java.base/share/classes/java/lang/String.java
Print this page
rev 54472 : 8221836: Avoid recalculating String.hash when zero
Reviewed-by: jrose, adinn
Contributed-by: peter.levart@gmail.com, claes.redestad@oracle.com
*** 162,171 ****
--- 162,177 ----
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,1523 ****
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
int h = hash;
! if (h == 0 && value.length > 0) {
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) {
hash = h;
}
}
return h;
}
--- 1512,1536 ----
* (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. Necessary restrictions 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, and that the computation is idempotent and derived
+ // from immutable state
int h = hash;
! if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
! if (h == 0) {
! hashIsZero = true;
! } else {
hash = h;
}
}
return h;
}
< prev index next >