package com.netflix.discovery.util; import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * An alternative to {@link String#intern()} with no capacity constraints. * * @author Tomasz Bak */ public class StringCache { public static final int LENGTH_LIMIT = 38; private static final StringCache INSTANCE = new StringCache(); private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final Map<String, WeakReference<String>> cache = new WeakHashMap<String, WeakReference<String>>(); private final int lengthLimit; public StringCache() { this(LENGTH_LIMIT); } public StringCache(int lengthLimit) { this.lengthLimit = lengthLimit; } public String cachedValueOf(final String str) { if (str != null && (lengthLimit < 0 || str.length() <= lengthLimit)) { // Return value from cache if available try { lock.readLock().lock(); WeakReference<String> ref = cache.get(str); if (ref != null) { return ref.get(); } } finally { lock.readLock().unlock(); } // Update cache with new content try { lock.writeLock().lock(); WeakReference<String> ref = cache.get(str); if (ref != null) { return ref.get(); } cache.put(str, new WeakReference<>(str)); } finally { lock.writeLock().unlock(); } return str; } return str; } public int size() { try { lock.readLock().lock(); return cache.size(); } finally { lock.readLock().unlock(); } } public static String intern(String original) { return INSTANCE.cachedValueOf(original); } }