4

In my Program I have a scenario, where Mutiple Thread will operate (put and get) on a single Map. Like Thread a using put a key/value in the map and the same time another thread is retrieving the key/value from the map for the same or different key. Now if I make my map synchronize then it wil be a big performance issue, so I decided to move to ConcurrentHashMap. During this scenario, I have another complexity that after certain period of time(not known to my application) few of the key/value pairs are not needed in my application, so I need to remove the same(Garbage Collection) to free memory. Though my programm doesn't have the idea that which key/values are not needed I thought to use weakrefernce. So, after ceratin period of time if the key(String) is not reachable it will be automatically garbage collected. I know the process to do the same in WeakhashMap but doesn't know the process to do it in ConcurrentHashMap. So, can anyone tell me how to do a weakrefernce in ConcurrentHashMap. Or else is there any other way to achieve the above scenario?

Souvik
  • 1,219
  • 3
  • 16
  • 38

1 Answers1

3

Looking through the WeakHashMap code it seems that there is no straight forward way of doing this but something of this following form should work: (This code has not actually been tested but I think it is at least on the correct path, also it only implements put and get, other operations can likewise be implemented)

public class MyMap<K, V> {

    private class MyKey<K> extends WeakReference<K> {         

        private final int hashCode;

        private MyKey(K k, ReferenceQueue<K> q) {
            super(k, q);
            hash = k.hashCode();
        }

        private MyKey(K k) {
            super(k);
            hash = k.hashCode();
        }

        @Override
        public int hashCode() {
            return hashCode;
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof MyKey)) {
                return false;
            }

            K otherKey = ((MyKey<K>) o).get();
            K myKey = get();
            if (otherKey != null && key != null) {
                return otherKey.equals(myKey);
            }

            return this == o;
        }
    }

    private final Map<MyKey<K>, V> map = new ConcurrentHashMap<MyKey<K>, V>();
    private final ReferenceQueue<K> queue = new ReferenceQueue<K>();

    public V put(K key, V val) {
        expungeStaleEntries();
        return map.put(new MyKey<K>(key, queue), val);    
    }

    public V get(K key) {
        expungeStaleEntries();
        return map.get(new MyKey<K>(key));
    }

    private void expungeStaleEntries() {
        MyKey<K> key = null;
        while ((key = (MyKey<K>) queue.poll()) != null) {
            map.remove(key);
        }
    }
}

Potential incorrectness of the above code aside, another caveat is that WeakHashMap works by calling its own expungeStaleEntries() method every time you call things like put(), get(), or even size(). The problem with this in the current scenario however is that ReferenceQueue.poll() does the actual polling inside of a synchronized block so cleaning up can slow you down (however it will not lock if the queue is empty so it will not undo all of the speed-improvement work ConcurrentHashMap is doing).

SamYonnou
  • 2,068
  • 1
  • 19
  • 23