简体   繁体   中英

Using HashMap.keySet as a dirty copy

I have a requirement where I have to use a hashMap where values can change dynamically and keys can get only inserted not deleted or updated. However Keys will be read many times and values may be updated many times.

For latency issues, I haven't made entire HashMap as ConcurrentHashMap in which case while writing keys I will have issues. I am fine with compromising slight data accuracy with keys. So I decided to keep my own dirty copy of keys. A code snippet like below.

package com.test.collections;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

public class CheckKeySet {

    private static Map<String, ConcurrentHashMap<String, String>> testMap = new HashMap<String, ConcurrentHashMap<String, String>>();

    public static void main(String[] args) {
        CheckKeySet trial = new CheckKeySet();
        try {
            trial.doIt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void doIt() throws InterruptedException {
        Thread accessThread1 = new AccessKeySet("Access1");
        Thread writeThread = new WriteValueSet();
        Thread accessThread2 = new AccessKeySet("Access2");
        Thread accessThread3 = new AccessKeySet("Access3");

        writeThread.start();
        Thread.sleep(1000);
        accessThread1.start();
        Thread.sleep(2000);
        accessThread2.start();
        Thread.sleep(4000);
        accessThread3.start();
    }

    private Set<String> getKeySet() {
        return new TreeSet<String>(testMap.keySet());
    }

    class AccessKeySet extends Thread {

        public AccessKeySet(String string) {
            super(string);
        }

        @Override
        public void run() {
            Set<String> keySet = getKeySet();
            System.out.println("###############Trying to print########## " + getName() + " keySet size " + keySet.size());
            for (String s : keySet) {
                System.out.println(s);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class WriteValueSet extends Thread {

        @Override
        public void run() {
            int i = 1;
            for (i = 1; i < 10000; i++) {
                testMap.put("Check-" + i, new ConcurrentHashMap<String, String>());
                System.out.println("Inserted " + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

My question, I am creating new Set Object in above implementation with the HashMap.keySet() as base value. HashMap.keySet() will live forever in my code. Will this impact the GC of dirty set objects that I am creating in getKeySet() ? I want this new set object to be cced whenever its holding object becomes eligible for gc. It should not be stopped from getting gced because hashMap.keySet is alive

Correct me if I'm wrong, but it sounds like you don't want keys or values to get garbage collected from testMap , unless you manually remove them. Rather, you only want keys in the key set returned by your getKeySet() method to be garbage collected, if at all possible, even you might not remove them explicitly from the set.

Assuming that is the case, you should consider using weak references . More precisely to your implementation, you could simulate a WeakHashSet (as per this answer ) and change your getKeySet() method implementation to:

private Set<String> getKeySet() {
  Set<String> cache = Collections.newSetFromMap(
    new WeakHashMap<String, Boolean>());
  cache.addAll(this.testMap.keySet());
  return cache;
}

This new code copies all of the keys of the strongly referenced testMap into the weakly referenced cache . Thus, whenever the garbage collector runs after you remove an element from testMap , the garbage collector will remove that same element automatically from cache .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM