我的应用程序中需要基于密钥的Semaphore机制,偶然发现了Guava的Striped.semaphore(int, int)。但是,它的行为不符合预期。

使用以下代码,提取有时会返回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:

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

代码中的基本假设似乎是,如果与特定对象关联的信号量具有许可,则该对象在映射中具有一个条目,但事实并非如此-如果映射中存在另一个对象的条目碰巧与相同的Semaphore相关联,则该许可可能由完全不同的对象上的fetch获取,该对象实际上在地图中没有条目。

08-28 11:50