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