/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util; import java.lang.ref.WeakReference; import java.util.WeakHashMap; import com.opengamma.util.async.AbstractHousekeeper; /** * Reduction of common object values to single instances. * * @param <T> object type to reduce */ public class WeakInstanceCache<T> { private static final class Housekeeper extends AbstractHousekeeper<WeakInstanceCache<?>> { protected Housekeeper(final WeakInstanceCache<?> target) { super(target); } @Override protected boolean housekeep(final WeakInstanceCache<?> target) { target.gc(); return true; } } /** * Use a pool of buckets in the way that the concurrent hash works to try and reduce collisions on the monitor. */ private static final int BUCKETS = 1024; @SuppressWarnings("unchecked") private final WeakHashMap<T, WeakReference<T>>[] _data = new WeakHashMap[BUCKETS]; public WeakInstanceCache() { for (int i = 0; i < BUCKETS; i++) { _data[i] = new WeakHashMap<T, WeakReference<T>>(); } (new Housekeeper(this)).start(); } protected T getImpl(final WeakHashMap<T, WeakReference<T>> data, final T value) { synchronized (data) { final WeakReference<T> canonRef = data.get(value); if (canonRef != null) { final T canonValue = canonRef.get(); if (canonValue != null) { return canonValue; } } data.put(value, new WeakReference<T>(value)); return value; } } public T get(final T value) { final WeakHashMap<T, WeakReference<T>> data = _data[value.hashCode() & (BUCKETS - 1)]; return getImpl(data, value); } protected void gc() { for (int i = 0; i < BUCKETS; i++) { _data[i].size(); } } }