java - Is this thread safe and efficient in java
问题描述
public class Test {
static ConcurrentHashMap<Integer, Integer> map = null;
final static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public static void open() {
lock.writeLock().lock();
try {
if (map != null) {
return;
}
map = new ConcurrentHashMap<>();
} finally {
lock.writeLock().unlock();
}
}
public static void close() {
final ConcurrentHashMap<Integer, Integer> concurrentHashMap;
lock.writeLock().lock();
try {
if (map == null) {
return;
}
concurrentHashMap = map;
map = null;
} finally {
lock.writeLock().unlock();
}
// deal with concurrentHashMap data
}
public static boolean put(final int key, final int value) {
lock.readLock().lock();
try {
if (map == null) {
return false;
}
if (map.putIfAbsent(key, value) != null) {
return false;
}
} finally {
lock.readLock().unlock();
}
return true;
}
public static boolean remove(final int key) {
lock.readLock().lock();
try {
if (map == null) {
return false;
}
if (map.remove(key) == null) {
return false;
}
} finally {
lock.readLock().unlock();
}
return true;
}
}
In the code above, when put() and remove(), use readLock instead of writeLock, they are most frequently used.When open() and close(), both use writeLock, they are less frequently used. The target is to improve concurrency. I am not sure about:
- Is it thread safe?
- Is it efficient?
I think both is yes. I know ConcurrentHashMap is thread safe. I want to know if this implementation is good or bad and why.
解决方案
线程安全:
从某种意义上说,它是线程安全的。一旦close
被调用,进一步调用put
不会remove
影响所concurrentHashMap
引用的地图的状态。
但是,调用nextput
和remove
在 next 之前open
将导致更新丢失。这让我觉得设计很糟糕……考虑到open
and的表面意义close
是避免丢失更新。这可能是另一个级别的线程安全问题。
效率:
一方面:我观察到地图的所有更新都是在您持有锁时执行的。鉴于此,我认为使用ConcurrentHashMap
. 使用常规HashMap
将是线程安全且更高效的。
另一方面,由于所有更新都是在持有锁的情况下执行的,所以锁是并发瓶颈,使用 a 的潜在并发优势ConcurrentHashMap
没有实际意义。
我想我会使用AtomicReference
(javadoc)来实现这个......并且没有锁。诀窍是使用ref.getAndSet(new ConcurrentHashMap())
将现有地图“切换”为新的空地图。
这AtomicReference
仍然是一个并发瓶颈,但程度要小得多,您可以通过将这两个操作作为单个原子操作执行来避免“关闭...打开”漏洞。
请参阅@Holger 的答案以获取使用AtomicReference
...的示例解决方案,注意他的版本没有解决“关闭...开孔”问题。
推荐阅读
- mysql - 使用 mySQL 将 Unix 时间戳转换为自定义的人类可读时间
- data-structures - Graph DataStructure中的简单路径和简单循环
- javascript - 如何根据 AngularJS 中的 url 显示/隐藏块
- android - 应用程序连接在服务器可以处理数据之前超时
- c# - 为什么未处理的异常技巧在所有情况下都不起作用
- sql - 如何计算 R 中 2 个时间戳之间的观察值(给出的示例)?
- c++ - 模板元编程 - 尝试实现维度分析
- python - 在 tensorflow2 中使用自定义数据生成器进行多线程处理
- java - Eclipse IDE 第一次没有打开
- vb.net - 使用 ComboBox 显示特定的 ImageList