首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >迭代WeakHashMap

迭代WeakHashMap
EN

Stack Overflow用户
提问于 2015-01-19 19:11:06
回答 1查看 970关注 0票数 10

我同时使用了一个WeakHashMap。我希望实现基于整数参数的细粒度锁定;如果线程A需要修改由整数a标识的资源,而线程B对由整数b标识的资源执行相同的操作,则它们不需要同步。但是,如果有两个线程使用相同的资源,假设线程C也在使用由整数锁标识的资源,那么线程A和C当然需要在相同的锁上同步。

当不再有需要ID为X的资源的线程时,则可以删除key=X映射中的锁。但是,此时可能会有另一个线程进入并尝试使用ID=X的Map中的锁,因此在添加/删除锁时需要全局同步。(这将是每个线程必须同步的唯一位置,与Integer参数无关)但是,线程不知道何时删除锁,因为它不知道自己是使用锁的最后一个线程。

这就是我使用WeakHashMap的原因:当不再使用该ID时,可以在GC需要时删除键值对。

为了确保我有一个已经存在的条目的键的强引用,以及形成映射键的对象引用,我需要迭代映射的keySet:

代码语言:javascript
复制
synchronized (mrLocks){
    // ... do other stuff
    for (Integer entryKey : mrLocks.keySet()) {
        if (entryKey.equals(id)) {
            key = entryKey;
            break;
        }
    }
    // if key==null, no thread has a strong reference to the Integer
    // key, so no thread is doing work on resource with id, so we can
    // add a mapping (new Integer(id) => new ReentrantLock()) here as
    // we are in a synchronized block. We must keep a strong reference
    // to the newly created Integer, because otherwise the id-lock mapping
    // may already have been removed by the time we start using it, and 
    // then other threads will not use the same Lock object for this
    // resource
}

现在,Map的内容可以在迭代时更改吗?我不这么认为,因为通过调用mrLocks.keySet(),我为迭代范围创建了一个对所有键的强引用。对吗?

EN

回答 1

Stack Overflow用户

发布于 2015-01-19 19:39:48

由于API没有对keySet()进行断言,因此我建议使用如下的缓存用法:

代码语言:javascript
复制
private static Map<Integer, Reference<Integer>> lockCache = Collections.synchronizedMap(new WeakHashMap<>());

public static Object getLock(Integer i)
{
    Integer monitor = null;
    synchronized(lockCache) {
        Reference<Integer> old = lockCache.get(i);
        if (old != null)
            monitor = old.get();

        // if no monitor exists yet
        if (monitor == null) {
            /* clone i for avoiding strong references 
               to the map's key besides the Object returend 
               by this method.
            */ 
            monitor = new Integer(i);
            lockCache.remove(monitor); //just to be sure
            lockCache.put(monitor, new WeakReference<>(monitor));
        }

    }

    return monitor;
}

这样,您在锁定监视器的同时持有对监视器(键本身)的引用,并允许GC在不再使用它时完成它。

编辑:

在评论中关于有效负载的讨论之后,我考虑了一个带有两个缓存的解决方案:

代码语言:javascript
复制
private static Map<Integer, Reference<ReentrantLock>> lockCache = new WeakHashMap<>();
private static Map<ReentrantLock, Integer> keyCache = new WeakHashMap<>();

public static ReentrantLock getLock(Integer i)
{
    ReentrantLock lock = null;
    synchronized(lockCache) {
        Reference<ReentrantLock> old = lockCache.get(i);
        if (old != null)
            lock = old.get();

        // if no lock exists or got cleared from keyCache already but not from lockCache yet
        if (lock == null || !keyCache.containsKey(lock)) {
            /* clone i for avoiding strong references 
               to the map's key besides the Object returend 
               by this method.
           */ 
            Integer cacheKey = new Integer(i); 
            lock = new ReentrantLock();
            lockCache.remove(cacheKey); // just to be sure
            lockCache.put(cacheKey, new WeakReference<>(lock));
            keyCache.put(lock, cacheKey);
        }                
    }

    return lock;
}

只要存在对有效负载(锁)的强引用,对keyCache中映射整数的强引用就可以避免从lockCache缓存中删除有效负载。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28023270

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档