簡體   English   中英

使用HashMap.keySet作為臟副本

[英]Using HashMap.keySet as a dirty copy

我有一個必須使用hashMap的要求,其中值可以動態更改,並且鍵只能插入而不刪除或更新。 但是,將多次讀取鍵,並且可能會多次更新值。

對於延遲問題,我沒有將整個HashMap做成ConcurrentHashMap,在這種情況下,編寫密鑰時會遇到問題。 我可以通過密鑰來降低數據的准確性。 因此,我決定保留自己的臟密鑰副本。 如下所示的代碼段。

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();
                }
            }
        }
    }
}

我的問題是,我在上述實現中使用HashMap.keySet()作為基值來創建新的Set對象。 HashMap.keySet()將永遠存在於我的代碼中。 這會影響我在getKeySet()中創建的臟集對象的GC嗎? 我希望只要它的持有對象有資格使用gc,就可以抄送這個新的set對象。 由於hashMap.keySet仍然存在,因此不應停止獲取gced

如果我錯了,請糾正我,但聽起來您不希望從testMap收集垃圾或鍵或值,除非您手動將其刪除。 相反,您只希望對getKeySet()方法返回的鍵集中的鍵進行垃圾回收,即使可能的話,即使您可能不明確地從鍵集中刪除它們也是如此。

假設是這種情況,您應該考慮使用弱引用 對於實現而言,您可以模擬一個WeakHashSet (按照此答案 ),並將您的getKeySet()方法實現更改為:

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

此新代碼將強引用的testMap所有鍵testMap到弱引用的cache 因此,每當從testMap刪除元素后運行垃圾收集器時,垃圾收集器都會從cache自動刪除該元素。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM