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;
}
}
在上面的代码中,当put()和remove()时,使用readLock而不是writeLock,它们是最常用的;当open()和close()时,它们都使用writeLock,它们的使用率较低。目标是提高并发性。我不确定:
我认为两者都是对的。我知道ConcurrentHashMap是线程安全的。我想知道此实施的好坏,为什么。
答案 0 :(得分:2)
从某种意义上说,它是线程安全的。调用close
之后,对put
和remove
的进一步调用将不会影响concurrentHashMap
所引用的地图的状态。
但是,在下一个put
之前调用remove
和open
会导致更新丢失。鉴于open
和close
的表面意义是要避免丢失更新,这令我感到不满意。这可能是另一个级别的线程安全问题。
一方面:我观察到在您持有锁的同时对地图进行了所有更新。鉴于此,我认为使用ConcurrentHashMap
没有任何意义。使用常规的HashMap
是线程安全的,并且效率更高。
另一方面,由于所有更新都是在持有锁的同时执行的,因此锁是一个并发瓶颈,使用ConcurrentHashMap
的潜在并发优势还没有意义。
我想我将使用AtomicReference
(javadoc)...且不加锁来实现这一点。诀窍是使用ref.getAndSet(new ConcurrentHashMap())
将现有地图“切换”为新的空地图。
AtomicReference
仍然是并发瓶颈,但程度要小得多,并且可以通过将这两个操作作为一个原子操作来避免“关闭...打开”漏洞。
有关使用AtomicReference
的示例解决方案,请参阅@Holger的答案...。请注意,他的版本无法解决“封闭...裸眼”问题。
答案 1 :(得分:2)
正如其他人所说,通过在此用例中使用AtomicReference
可以提高效率。但是,更重要的是,代码变得更加简单:
static final AtomicReference<ConcurrentHashMap<Integer, Integer>>
MAP = new AtomicReference<>();
public static void open() {
MAP.compareAndSet(null, new ConcurrentHashMap<>());
}
public static void close() {
ConcurrentHashMap<Integer, Integer> map = MAP.getAndSet(null);
if(map != null) {
// deal with map data
}
}
public static boolean put(final int key, final int value) {
ConcurrentHashMap<Integer, Integer> map = MAP.get();
return map != null && map.putIfAbsent(key, value) == null;
}
public static boolean remove(final int key) {
ConcurrentHashMap<Integer, Integer> map = MAP.get();
return map != null && map.remove(key) != null;
}