簡體   English   中英

這個線程在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;
}

}

在上面的代碼中,當put()和remove()時,使用readLock而不是writeLock,它們是最常用的;當open()和close()時,它們都使用writeLock,它們的使用率較低。 目標是提高並發性。 我不確定:

  1. 它是線程安全的嗎?
  2. 有效率嗎?

我認為兩者都是。 我知道ConcurrentHashMap是線程安全的。 我想知道此實現的好壞,為什么。

線程安全性:

從某種意義上說,它是線程安全的。 調用close之后,進一步的putremove調用將不會影響concurrentHashMap引用的地圖的狀態。

但是,在下一次open之前調用putremove將導致更新丟失。 考慮到openclose是避免丟失更新,因此這讓我感到很不滿意。 這可能是另一個級別的線程安全問題。

效率:

一方面:我觀察到在您持有鎖的同時對地圖的所有更新都已執行。 鑒於此,我認為使用ConcurrentHashMap沒有任何意義。 使用常規的HashMap將是線程安全的,並且效率更高。

另一方面,由於所有更新都是在持有該鎖的同時執行的,因此該鎖是並發瓶頸,使用ConcurrentHashMap的潛在並發優勢尚無定論。


我想我會使用AtomicReferencejavadoc )...來實現它,並且沒有鎖。 訣竅是使用ref.getAndSet(new ConcurrentHashMap())將現有地圖“切換”為新的空地圖。

AtomicReference仍將是並發瓶頸,但程度要小得多,並且可以通過將這兩個操作作為單個原子操作進行操作來避免“關閉...打開”漏洞。

有關使用AtomicReference的示例解決方案,請參見@Holger的答案...,請注意,他的版本無法解決“封閉...裸眼”問題。

正如其他人所說,可以通過針對此用例使用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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM