Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这个线程在java中是安全和高效的吗_Java_Multithreading_Concurrency_Thread Safety_Concurrenthashmap - Fatal编程技术网

这个线程在java中是安全和高效的吗

这个线程在java中是安全和高效的吗,java,multithreading,concurrency,thread-safety,concurrenthashmap,Java,Multithreading,Concurrency,Thread Safety,Concurrenthashmap,} 在上面的代码中,在放置和删除时,使用readLock而不是writeLock,它们是最常用的。在打开和关闭时,都使用writeLock,它们的使用频率较低。目标是提高并发性。我不确定: 它是线程安全的吗? 效率高吗? 我认为两者都是肯定的。我知道ConcurrentHashMap是线程安全的。我想知道这个实现是好是坏以及原因。线程安全: 从某种意义上说,它是线程安全的。调用close后,进一步调用put和remove不会影响concurrentHashMap引用的映射的状态 但是,在下次打开

}

在上面的代码中,在放置和删除时,使用readLock而不是writeLock,它们是最常用的。在打开和关闭时,都使用writeLock,它们的使用频率较低。目标是提高并发性。我不确定:

它是线程安全的吗? 效率高吗? 我认为两者都是肯定的。我知道ConcurrentHashMap是线程安全的。我想知道这个实现是好是坏以及原因。

线程安全: 从某种意义上说,它是线程安全的。调用close后,进一步调用put和remove不会影响concurrentHashMap引用的映射的状态

但是,在下次打开之前调用put和remove将导致更新丢失。这给我的印象是糟糕的设计。。。考虑到开放和关闭的表面目的是避免丢失更新。这可能是另一个级别的线程安全问题

效率: 一方面:我观察到所有地图更新都是在您持有锁的情况下执行的。鉴于此,我认为使用ConcurrentHashMap没有任何意义。使用常规HashMap将是线程安全和更高效的

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

我想我应该使用原子引用来实现它。。。没有锁。诀窍是使用ref.getAndSetnew ConcurrentHashMap将现有映射切换为新的空映射

原子引用仍然是一个并发瓶颈,但程度要小得多,而且您可以避免关闭。。。通过将两个动作作为单个原子操作来打开孔


有关使用原子引用的示例解决方案,请参见@Holger的答案。。。注意到他的版本没有提到结尾。。。裸眼问题。

正如其他人所说,通过使用此用例的原子参考,可以提高效率。但是,也许更重要的是,代码变得更简单:

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;
}

ConcurrentHashMap的实现是线程安全和并发的。为什么不让map本身成为最终的呢?为什么要处理它为空?实现似乎没有添加任何内容,现在每个putIfAbsent和remove都有全局锁,而直接使用CHM时没有全局锁,所以我认为实现是不好的。实现提供的一件事是原子清晰,我认为CHM没有。如果这很重要,也许考虑一下AtomicReference。也可以是无锁的。@KhalidShah,锁的作用是保护map变量,而不是保护map的内容。如果没有锁定,不同的线程可能会在哪个ConcurrentHashMap实例是当前实例的问题上产生分歧。1。有了锁,我想不能使用HashMap,因为多线程会调用put方法。2.使用AtomicReference,无法将现有映射切换为新的空映射,因为当调用close方法时,在有人调用open之前,没有人可以再调用put。3.使用AtomicReference,您无法在关闭时安全地处理旧数据,因为当您迭代旧映射时,另一个线程可能会获得旧映射引用,并将数据放入旧映射。如果有其他线程使用映射而未使用打开和关闭或获取锁,则您的应用程序不是线程安全的。如果你想准确回答你的问题,你应该包括所有相关的代码。请编辑您的问题以添加其他线程如何访问/迭代/更新映射的示例。您无法在close中正确处理旧数据,因为当线程A迭代器关闭旧映射时,线程B in put可能获得旧映射引用,并且正在将数据放入旧映射。这样,线程B的新put数据可能不会在线程A的关闭迭代器中接触。如果您是对的,当前映射与null的原子交换并不排除线程已经拥有映射。这可以用一个AtomicStampedReference来修复,它维护正在进行的更新的数量,但是这与使用ReentrantReadWriteLock没有太大区别。
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;
}