1 package com.fasterxml.jackson.core.util;
2
3 import java.util.LinkedHashMap;
4 import java.util.concurrent.ConcurrentHashMap;
5
6 /**
7 * Singleton class that adds a simple first-level cache in front of
8 * regular String.intern() functionality. This is done as a minor
9 * performance optimization, to avoid calling native intern() method
10 * in cases where same String is being interned multiple times.
11 *<p>
12 * Note: that this class extends {@link LinkedHashMap} is an implementation
13 * detail -- no code should ever directly call Map methods.
14 */
15 public final class InternCache
16 extends ConcurrentHashMap<String,String> // since 2.3
17 {
18 private static final long serialVersionUID = 1L;
19
20 /**
21 * Size to use is somewhat arbitrary, so let's choose something that's
22 * neither too small (low hit ratio) nor too large (waste of memory).
23 *<p>
24 * One consideration is possible attack via colliding {@link String#hashCode};
25 * because of this, limit to reasonably low setting.
26 */
27 private final static int MAX_ENTRIES = 180;
28
29 public final static InternCache instance = new InternCache();
30
31 /**
32 * As minor optimization let's try to avoid "flush storms",
33 * cases where multiple threads might try to concurrently
34 * flush the map.
35 */
36 private final Object lock = new Object();
37
38 private InternCache() { super(MAX_ENTRIES, 0.8f, 4); }
39
40 public String intern(String input) {
41 String result = get(input);
42 if (result != null) { return result; }
43
44 /* 18-Sep-2013, tatu: We used to use LinkedHashMap, which has simple LRU
45 * method. No such functionality exists with CHM; and let's use simplest
46 * possible limitation: just clear all contents. This because otherwise
47 * we are simply likely to keep on clearing same, commonly used entries.
48 */
49 if (size() >= MAX_ENTRIES) {
50 /* Not incorrect wrt well-known double-locking anti-pattern because underlying
51 * storage gives close enough answer to real one here; and we are
52 * more concerned with flooding than starvation.
53 */
54 synchronized (lock) {
55 if (size() >= MAX_ENTRIES) {
56 clear();
57 }
58 }
59 }
60 result = input.intern();
61 put(result, result);
62 return result;
63 }
64 }
65
66