首页 > 解决方案 > 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:

  1. Is it thread safe?
  2. 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.

标签: javamultithreadingconcurrencythread-safetyconcurrenthashmap

解决方案


线程安全:

从某种意义上说,它是线程安全的。一旦close被调用,进一步调用put不会remove影响所concurrentHashMap引用的地图的状态。

但是,调用nextputremove在 next 之前open将导致更新丢失。这让我觉得设计很糟糕……考虑到openand的表面意义close是避免丢失更新。这可能是另一个级别的线程安全问题。

效率:

一方面:我观察到地图的所有更新都是在您持有锁时执行的。鉴于此,我认为使用ConcurrentHashMap. 使用常规HashMap将是线程安全且更高效的。

另一方面,由于所有更新都是在持有锁的情况下执行的,所以锁是并发瓶颈,使用 a 的潜在并发优势ConcurrentHashMap没有实际意义。


我想我会使用AtomicReferencejavadoc)来实现这个......并且没有锁。诀窍是使用ref.getAndSet(new ConcurrentHashMap())将现有地图“切换”为新的空地图。

AtomicReference仍然是一个并发瓶颈,但程度要小得多,您可以通过将这两个操作作为单个原子操作执行来避免“关闭...打开”漏洞。

请参阅@Holger 的答案以获取使用AtomicReference...的示例解决方案,注意他的版本没有解决“关闭...开孔”问题。


推荐阅读