package common; import java.util.Arrays; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public abstract class AbstractObjectPool<K, V> { private Map<K, Instance<V>> pool; private volatile int maxSize; public static final int DEFAULT_MAX_SIZE = 0xff; public AbstractObjectPool(int maxSize) { this.maxSize = maxSize; this.pool = new ConcurrentHashMap<K, Instance<V>>(); } public AbstractObjectPool() { this.maxSize = DEFAULT_MAX_SIZE; this.pool = new ConcurrentHashMap<K, Instance<V>>(); } private static final class Instance<V> { private volatile int weight; private final V value; public Instance(V value) { if (value == null) throw new NullPointerException(); this.weight = 1; this.value = value; } public int getWeight() { return weight; } public V getValue() { return value; } public synchronized void addWeight() { if (weight < Integer.MAX_VALUE) weight++; } } private void flushPool() { // pool.clear(); int median = getMedian(); for (Map.Entry<K, Instance<V>> entry : pool.entrySet()) { if (entry.getValue().getWeight() < median) pool.remove(entry.getKey()); } if (pool.size() > maxSize * 0.75 && maxSize < (Integer.MAX_VALUE >> 1)) synchronized (this) { maxSize <<= 1; } } private int getMedian() { int[] weights = new int[pool.size()]; int i = 0; for (Map.Entry<K, Instance<V>> entry : pool.entrySet()) { weights[i++] = entry.getValue().getWeight(); } Arrays.sort(weights); return weights[weights.length / 2]; } private void addInstance(K key, V value) { Instance<V> instance = new Instance<V>(value); pool.put(key, instance); } public final V getInstance(K key) { Instance<V> instance = pool.get(key); if (instance != null) { instance.addWeight(); return instance.getValue(); } if (pool.size() + 1 > maxSize) flushPool(); V instanceValue = newInstance(key); addInstance(key, instanceValue); return instanceValue; } public abstract V newInstance(K key); @Override public String toString() { return pool.toString(); } }
測試類:java
package test; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import org.apache.commons.lang3.time.DateFormatUtils; import org.junit.Test; import com.bankwel.portal.common.util.AbstractObjectPool; public class DateFormatTest { private static AbstractObjectPool<String, SimpleDateFormat> formatPool = new AbstractObjectPool<String, SimpleDateFormat>() { @Override public SimpleDateFormat newInstance(String key) { return new SimpleDateFormat(key); } }; private SimpleDateFormat _getFormat(String key) { return formatPool.getInstance(key); } private static final Random RANDOM = new Random(); private static final String[] SPLITORS = { "/", ",", "-", ".", " ", ":", ";", "|", "*" }; private static String getRandomPattern() { return new StringBuilder().append("yyyy").append(getRandomSplitor()).append("MM").append(getRandomSplitor()) .append("dd").toString(); } private static String getRandomSplitor() { return SPLITORS[RANDOM.nextInt(SPLITORS.length)]; } private static final Date NOW = new Date(); private static Date getRandomDate() { return NOW; } @Test public void testLocal() { for (int i = 0; i < 10000; i++) _getFormat(getRandomPattern()).format(getRandomDate()); } @Test public void testApache() { for (int i = 0; i < 10000; i++) DateFormatUtils.format(getRandomDate(), getRandomPattern()); } @Test public void testJdk() { for (int i = 0; i < 10000; i++) { SimpleDateFormat format = new SimpleDateFormat(getRandomPattern()); format.format(getRandomDate()); } } public static void main(String[] args) { for (int i = 0; i < 100; i++) System.out.println(getRandomSplitor()); } }
測試結果:apache