Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.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 锁写入HashMap_Java_Multithreading_Concurrency - Fatal编程技术网

Java 锁写入HashMap

Java 锁写入HashMap,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有一个正在异步更新的HashMap。我需要执行涉及映射的操作,这些操作要求映射在任务期间不改变状态,例如根据映射的内容对值进行排序 有没有一种方法可以锁定一个映射,这样只会发生读操作,这会阻止所有的写线程,这样在映射被解锁之后,所有的修改都会发生?当我使用ConcurrentHashMap时,锁需要能够允许多个线程同时写入,我想利用ConcurrentHashMap的优点。ConcurrentHashMap不提供方法调用之间的线程安全,只在单个调用中提供。因此,如果希望在执行操作时保持映射不变

我有一个正在异步更新的HashMap。我需要执行涉及映射的操作,这些操作要求映射在任务期间不改变状态,例如根据映射的内容对值进行排序


有没有一种方法可以锁定一个映射,这样只会发生读操作,这会阻止所有的写线程,这样在映射被解锁之后,所有的修改都会发生?当我使用ConcurrentHashMap时,锁需要能够允许多个线程同时写入,我想利用ConcurrentHashMap的优点。

ConcurrentHashMap不提供方法调用之间的线程安全,只在单个调用中提供。因此,如果希望在执行操作时保持映射不变,则需要使用自己的锁包装对映射的调用

例如,使用ReadWriteLock:

ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
当您更新地图时

readWriteLock.writeLock().lock();

// do the updates

readWriteLock.writeLock().unlock();
当你想看地图的时候

readWriteLock.readLock().lock();

// perform the read and its operations that rely on the map not changing

readWriteLock.readLock().unlock();

为什么不使用受可重入写回保护的
ConcurrentHashMap
,而是反向使用

myLock.writeLock().lock();
try {
    return myMap.get(...);
} finally {
    myLock.writeLock().unlock();
}

这非常难看,需要在注释中进行说明,以警告未经培训的后续开发人员,您在按住
readLock
时实际上正在编写,在按住
writeLock
时正在阅读,但我不明白为什么它不起作用

为了清晰起见,您甚至可以编写自己的
inversedreentrandretrawritelock
,它封装了真实的
reentrandretrawritelock
,以反转调用并使代码更具可读性


如@GPI所建议的,如果您希望处于读模式或写模式,但在该模式下保持并发性,则可以使用
AtomicInteger
AtomicLong
实现锁定。正值表示处于读取模式,负值表示处于写入模式。处于零表示锁可以进入任一模式。这会立即变得更加复杂,因为您必须自己实现锁,而上面概述的具有独占读取的并发写入解决方案仅依赖于现有的API类。(如果您愿意,我肯定可以找到一个答案,但我无法立即提供答案)

将HashMap包装到一个类中,在该类中放置某种类型的

boolean isLocked
假设您想从一个线程开始读取进程,您可以检查这个锁

if(!myClass.getLockState())
{ //perform whatever you want to do }

如果您确保所有线程都使用相同的
myClass
对象,这可能是锁定/解锁hashMap的简单解决方案。

为什么不尝试使用ConcurrentHashMap?@TugrulAsik:ConcurrentHashMap没有选项锁定整个对象,使用单独的锁会破坏使用ConcurrentHashMap的好处。您还可以在常规HashMap周围包装一个锁。感谢您对ConcurrentHashMap的解释。在ConcurrentHashMap周围包装一个ReadWriteLock,让写入程序使用读锁,长时间运行的读操作使用写锁,这可能会带来性能优势,如果一次只执行一个长时间运行的读取操作,那么能够容忍地图在其下更改的读者两者都不会使用。不过,我担心双重同步开销。也许可以计时,看看它与受常规锁保护的HashMap相比如何。@user2248702如果有解决您问题的答案,您应该接受:)据我所知,ReadWriteLock一次只允许一个写入线程,这是正确的吗?如果是,我可以用什么来编写多线程?@user2248702-您可以使用
ConcurrentHashMap
来实现这一点,但有一个额外的缺点-所有的写操作都不会在后续的读取中看到。@user2248702您的理解是正确的,ReadWriteLock是单写多读。多个作者将很难实现。你可以按照老兄的建议,或者在地图上画条。也就是说,有一个外部映射,它包装了n个其他映射,其中每个代理映射都有自己的读/写锁。然后可以通过键的hashcode选择代理映射。但首先,我建议保持简单,并在增加复杂性之前演示单个编写器解决方案的瓶颈?没有任何地方表明,当你锁定writeLock时,你一定是在写作。我知道这很难看,但你可以用readLock()写,用writeLock()读。@Rich lol。你说得对,这很难看。但它将实现OP的要求。我质疑多个作者和单个读者的语义。。听起来这里有一个更大的设计问题。也许更详细地说明为什么会出现这种情况会有所帮助。我不确定。。。虽然很难看,但它似乎符合我的要求。这将导致读取是单线程的。我认为OP考虑了(多线程读取)或(多线程写入),带有“或”互斥性。注释代码应该始终是最后的手段——只有当您正在做一些非常邪恶的事情,没有其他方法来解释它时才使用:在添加注释之前,我会尝试用类名和方法名将ReadWriteLock包装到另一个类中,这些类名和方法名可以解释发生了什么。好的,因此线程a调用geetLockState(),发现它是错误的,并开始做任何事情。如果此时线程B锁定锁并更改映射的内容,会发生什么情况?@james large hmmmm你是对的……愚蠢的我:)但是如果你可以将所有修改的“请求”放在
concurrentLinkedQueue
中,并且一个线程实际读取该队列并对映射执行更改,会发生什么情况?所有其他线程都是只读访问。
if(!myClass.getLockState())
{ //perform whatever you want to do }