Guava 基于键的信号量与 ConcurrentHashMap 中的信号量
Key based Semaphores with Guava vs Semaphores in a ConcurrentHashMap
我需要一个基于 Semaphore mechanism in my application and stumbled upon Striped.semaphore(int, int) Guava 的密钥。但是,它的行为并不像预期的那样。
使用以下代码,有时会获取 returns 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:
The guarantee provided by this class is that equal keys lead to the same lock (or semaphore), i.e. if (key1.equals(key2)) then striped.get(key1) == striped.get(key2) (assuming Object.hashCode() is correctly implemented for the keys). Note that if key1 is not equal to key2, it is not guaranteed that striped.get(key1) != striped.get(key2); the elements might nevertheless be mapped to the same lock. The lower the number of stripes, the higher the probability of this happening.
您的代码中的基本假设似乎是,如果与特定对象关联的信号量具有许可,则该对象在映射中有一个条目,但事实并非如此——如果在恰好与同一 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));
}
我需要一个基于 Semaphore mechanism in my application and stumbled upon Striped.semaphore(int, int) Guava 的密钥。但是,它的行为并不像预期的那样。
使用以下代码,有时会获取 returns 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:
The guarantee provided by this class is that equal keys lead to the same lock (or semaphore), i.e. if (key1.equals(key2)) then striped.get(key1) == striped.get(key2) (assuming Object.hashCode() is correctly implemented for the keys). Note that if key1 is not equal to key2, it is not guaranteed that striped.get(key1) != striped.get(key2); the elements might nevertheless be mapped to the same lock. The lower the number of stripes, the higher the probability of this happening.
您的代码中的基本假设似乎是,如果与特定对象关联的信号量具有许可,则该对象在映射中有一个条目,但事实并非如此——如果在恰好与同一 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));
}