package net.rubyeye.xmemcached.utils; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.management.RuntimeErrorException; public class CachedString { private static ConcurrentHashMap<String, Reference<byte[]>> table = new ConcurrentHashMap(); static final ReferenceQueue rq = new ReferenceQueue(); public static byte[] getBytes(String s) { if (s == null || s.length() == 0) return null; byte[] bs = null; Reference<byte[]> existingRef = table.get(s); if (existingRef == null) { clearCache(rq, table); bs = s.getBytes(ByteUtils.DEFAULT_CHARSET); existingRef = table.putIfAbsent(s, new WeakReference<byte[]>(bs, rq)); } if (existingRef == null) { return bs; } byte[] existingbs = existingRef.get(); if (existingbs != null) { return existingbs; } // entry died in the interim, do over table.remove(s, existingRef); return getBytes(s); } static public <K, V> void clearCache(ReferenceQueue rq, ConcurrentHashMap<K, Reference<V>> cache) { // cleanup any dead entries if (rq.poll() != null) { while (rq.poll() != null) ; for (Map.Entry<K, Reference<V>> e : cache.entrySet()) { Reference<V> val = e.getValue(); if (val != null && val.get() == null) { cache.remove(e.getKey(), val); } } } } private static long testString(int keyLen) { String k = getKey(keyLen); long len = 0; for (int i = 0; i < 1000; i++) { // byte[] bs = k.getBytes(ByteUtils.DEFAULT_CHARSET); // String nk = new String(bs, ByteUtils.DEFAULT_CHARSET); byte[] bs = getBytes(k); String nk = ByteUtils.getString(bs); if (!k.equals(nk)) { throw new RuntimeException(); } len += nk.length(); } return len; } private static String getKey(int len) { StringBuilder sb = new StringBuilder(); String[] chars = { "a", "b", "c", "d", "e", "f", "g", "h" }; int index = (int) Math.floor(Math.random() * 8); for (int i = 0; i < len; i++) { sb.append(chars[index]); } return sb.toString(); } public static void main(String[] args) { long sum = 0; for (int i = 0; i < 10000; i++) { sum += testString(8); } int[] keys = { 8, 64, 128 }; for (int k : keys) { long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { sum += testString(k); } System.out.println("Key length=" + k + ", cost " + (System.currentTimeMillis() - start) + " ms."); } System.out.println(sum); System.out.println(table.size()); } }