I found this code on Peter Lawry's blog here. He mentions that this class doesn't require any further synchronization.
I am trying to improve my knowledge of concurrency and how to avoid unnecessary synchronization so am trying to figure how to reason about this case from a java memory model point of view.
The reference to the string array is final and the string themselves are immutable but the references to the strings contained in the array are mutable
- Isn't it at least theoretically possible that one thread could still see null after another thread has updated a value?
- Or is it the case that we don't care if the string is interned more than once?
Or does the JVM provide some additional guarantee that I am missing?
public class StringInterner { private final String[] interner; private final int mask; public StringInterner(int capacity) { int n = Maths.nextPower2(capacity, 128); interner = new String[n]; mask = n - 1; } private static boolean isEqual(@Nullable CharSequence s, @NotNull CharSequence cs) { if (s == null) return false; if (s.length() != cs.length()) return false; for (int i = 0; i < cs.length(); i++) if (s.charAt(i) != cs.charAt(i)) return false; return true; } @NotNull public String intern(@NotNull CharSequence cs) { long hash = 0; for (int i = 0; i < cs.length(); i++) hash = 57 * hash + cs.charAt(i); int h = (int) Maths.hash(hash) & mask; String s = interner[h]; if (isEqual(s, cs)) return s; String s2 = cs.toString(); return interner[h] = s2; } }