繁体   English   中英

在 ConcurrentHashMap 中使用 Guava 的基于键的信号量 vs 信号量

[英]Key based Semaphores with Guava vs Semaphores in a ConcurrentHashMap

我的应用程序中需要一个基于键的信号量机制,并且偶然发现了Guava 的 Striped.semaphore(int, int) 但是,它的行为并不像预期的那样。

使用以下代码,fetch 有时会返回 null。 这两种方法都由不同的线程访问。 我希望调用 fetch 的线程等待直到地图中的 Blubb 可用。

private final Striped<Semaphore> semaphores = Striped.semaphore(64, 0);

private final Map<String, Blubb> blubbs = Collections.synchronizedMap(new HashMap<String, Blubb>());

private Semaphore getSemaphore(final String key) {
    return semaphores.get(key);
}

@Override
public void put(String key, Blubb blubb)  {
    blubb.put(key, blubb);
    final Semaphore semaphore = getSemaphore(toUser);
    semaphore.release();
}

@Override
public blubb fetch(final String key) {
    try {
        final Semaphore semaphore = getSemaphore(key);
        final boolean acquired = semaphore.tryAcquire(30, TimeUnit.SECONDS);
        return blubbs.get(key);
    } catch (final InterruptedException e) {
        e.printStackTrace();
    }

    return null;
}

如果我使用以下代码切换回基本 Java,一切都会按预期进行。

private final Map<String, Semaphore> semaphoresMap = new ConcurrentHashMap<String, Semaphore>();

private Semaphore getSemaphore(final String key) {
    Semaphore semaphore = semaphoresMap.get(key);
    if (semaphore == null) {
        semaphore = new Semaphore(0);
        semaphoresMap.put(key, semaphore);
    }
    return semaphore;
}

我在这里缺少什么? 谢谢

Guava 的Striped指定多个键可能映射到同一个信号量。 来自 Javadoc:

此类提供的保证是相等的键导致相同的锁(或信号量),即 if (key1.equals(key2)) then striped.get(key1) == striped.get(key2)(假设 Object.hashCode () 正确实现了键)。 注意如果key1不等于key2,不保证striped.get(key1) != striped.get(key2); 尽管如此,元素可能会映射到同一个锁。 条纹数量越少,发生这种情况的概率就越高。

您代码中的基本假设似乎是,如果与特定对象关联的信号量具有许可,则该对象在映射中具有条目,但事实并非如此——如果映射中存在另一个对象的条目恰好与相同的Semaphore相关联,那么该许可可能会被一个完全不同的对象的fetch ,该对象实际上在映射中没有条目。

'basic java' 示例有一个潜在的竞争条件,computeIfAbsent 是一个原子操作并解决了这个问题:

private final Map<String, Semaphore> semaphoresMap = new ConcurrentHashMap<String, Semaphore>();

private Semaphore getSemaphore(final String key) {
    return semaphoresMap.computeIfAbsent(key, (String absentKey) -> new Semaphore(0));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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