问题标签 [reentrantreadwritelock]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
134 浏览

java - WeakHashMap 和 ReentrantReadWriteLock

我使用 Wea​​kHashMap 和 ReentrantReadWriteLock 实现了一个缓存,我的代码是这样的:

我的问题是,如果 gc 在读锁之后if(CACHE.containsKey(t))但之前执行K result = CACHE.get(t);并导致这if(CACHE.containsKey(t))是真的,但K result = CACHE.get(t);会变为空。

0 投票
1 回答
243 浏览

scala - Scala中单子内的可重入锁

我的一位同事就ReentrantReadWriteLock在一些 Scala 代码中使用 Java 进行了如下陈述:

在这里获取锁是有风险的。它是“可重入的”,但这在内部取决于线程上下文。F可以在不同线程中运行相同计算的不同阶段。你很容易造成死锁。

F这里指的是一些有效的单子。

基本上我要做的是在同一个单子中两次获取相同的可重入锁。

有人可以澄清为什么这可能是一个问题吗?

代码分为两个文件。最外层:

然后,在store

writeLock两段代码中的 the 是相同的,它是一个cats.effect.Resource[F, Unit]包装ReentrantReadWriteLocka writeLock。我以这种方式编写代码有一些原因,所以我不想深入研究。我只是想了解为什么(至少根据我的同事的说法),这可能会破坏一些东西。

另外,我想知道 Scala 中是否有一些替代方法可以允许这样的事情而不会出现死锁的风险。

0 投票
1 回答
80 浏览

java-8 - 多个延迟消费者、并发句柄、BlockingQueue

注意:我真的试图简化这段代码

我有多个 Runnable 执行的多个进程(不同类型)。

我试图用图表来简化这种情况。

在此处输入图像描述

我有一个RunnableProducer生产它的时间,生产的是转移到一个RunnableWorker执行一些操作ProcessorDown蓝色箭头)执行一个过程,并将其分发给它的接收者(同类型的类)。如果RunnableWorker被标记(code非空),它必须执行一种特殊类型的过程Processor并将其返回给传输它的“父级” RunnableWorker。也就是说,您的接收器收集了许多执行另一个附加ProcessorUp绿色箭头注意绿色箭头的数量。初始RunnableWorker传输(在同一类的中介的帮助下)所有数据到RunnableConsumer不混合它们的情况下,谁将执行另一个任务(对于这个问题,print)。

RunnableProducer应该只在最终RunnableConsumer可以接收/收集所有产生的东西(由 转移RunnableWorker's)时产生。RunnableProducer可以独立关闭。但是,RunnableConsumer必须在RunnableProducer生产时运行,直到他消耗掉所有东西(及其变体)。

注意:您可以复制、粘贴、编译和运行

该类ChunkDTO包含数据、索引(位置)和代码(以方便其分类RunnableConsumer)。

Counter,以便控制RunnableConsumer/RunnableWorker应该期望的内容。

如果RunnableProducer产生 7,并且有 5 个代码,则RunnableConsumer最终应该收集 35。rw11应该收集,而rw12 应该收集。RunnableWorker3*7=21 RunnableWorker2*7=14

创建该类LifeCycle是为了控制 LifeCycle Producer 和 Consumer,我仍然没有RunnableWorker.

RunnableWorker两个Runnable,以处理转移他们的孩子(//RUNNABLE DISTRIBUTOR)和父母(//RUNNABLE COLLECTOR)。

输出

如您所见,生产者发送了 5 个块,但我损失了大部分,我需要收到 25 个(对于本示例)。消费者只收集了少量物品。我的逻辑有什么问题?

我不知道创建两个 runnable 是否是 RunnableWorker 类的好解决方案。有没有更好的实现方式?

我认识到我有一种可怕的方法来阻止生产者等待消费者。您推荐什么解决方案?

0 投票
2 回答
435 浏览

java - 尽管地图是使用 ReentrantReadWriteLock 更新的,但访问地图会产生 java.util.ConcurrentModificationException

我们有一个 Spring Boot 服务,它只是提供来自地图的数据。地图会定期更新,由调度程序触发,这意味着我们构建一个新的中间地图,加载所有需要的数据,一旦完成,我们就会分配它。为了克服并发问题,我们引入了一个 ReentrantReadWriteLock,它在中间映射分配发生的那一刻打开一个写锁,当然在访问映射时打开一个读锁。请参阅下面的简化代码

如果我们将服务设置为负载访问地图很多,我们仍然会在日志中看到 java.util.ConcurrentModificationException 发生,我不知道为什么。

BTW:同时我也看到了这个问题,这似乎也是一个解决方案。不过,我想知道我做错了什么,或者我是否误解了 ReentrantReadWriteLock 的概念

编辑:今天我得到了完整的堆栈跟踪。正如你们中的一些人所说,这个问题实际上与这段代码无关,它只是在重新加载发生的同时巧合发生。问题实际上在于对 getSomeObject() 的访问。在实际代码中, SomeObject 又是一个 Map ,并且每次访问这个内部 List 时都会对其进行排序(无论如何这都很糟糕,但这是另一个问题)。所以基本上我们遇到了这个问题

0 投票
3 回答
788 浏览

java - ReentrantReadWriteLock 中是否有任何 WriteLock 优先于 ReadLock

我读过java文档:ReentrantReadWriteLock

而且我没有看到 writeLock 比 readLock 有任何优先级

但我也读过这样的主题:ReentrantReadWriteLock 中的读写锁是否有某种关联?
我在两个答案中都看到了以下短语:

如果锁被读者持有并且线程请求写锁,则不允许更多的读者获得读锁,直到获得写锁的线程释放它。


喜欢作家胜过读者。也就是说,如果写入者正在等待锁,则不允许来自其他线程的新读取者访问该资源。现有读者可以继续使用该资源,直到他们释放锁。这可以防止所谓的“作家饥饿”。

这些短语听起来很有意义,看起来我已经在其他地方读过。

但显然它与java doc是矛盾的。

它在最新的 JDK 中是否发生了变化?它仍然有效吗?

如何防止作家饿死?

0 投票
2 回答
492 浏览

java - 与 ReentrantLock 相比,ReentrantReadWriteLock 的性能非常差

我创建了 1000 个线程来增加,1000 个线程来减少,1000 个线程来读取值。

每增加一个线程,值增加 25000 倍。

每个递减线程,将值减少 25000 倍。

每个读取线程,读取值 50000 次。

所以所有的操作都是读取主导的。

读取值时放置 ReadLock

并且 WriteLock 用于增加和减少值的方法。

观察到:ReentrantReadWriteLock 大约需要 13000 毫秒,锁定大约需要 3000 毫秒。预期:ReentrantReadWriteLock 提供比 ReentrantLock 更快的性能。

顺便说一句:我个人认为使用 getCounter 方法时不需要锁定/同步(只需读取值)

0 投票
1 回答
306 浏览

java - ReentrantReadWriteLock 在 ConcurrentHashMap::compute() 中使用时挂起

TL;DR - 在我的应用程序中,许多线程在通过 compute() 方法将条目插入 ConcurrentHashMap 时以 READ 模式获取 ReentrantReadWriteLock,并在传递给 compute() 的 lamdba 完成后释放 READ 锁。有一个单独的线程在 WRITE 模式下获取 ReentrantReadWriteLock 并非常(非常)快速地释放它。虽然这一切都在发生,但 ConcurrentHashMap 正在调整大小(增长和缩小)。我遇到了挂起,我总是在堆栈跟踪中看到在调整大小期间调用的 ConcurrentHashMap::transfer()。所有线程都被阻塞等待获取我的 ReentrantReadWriteLock。转载者:https ://github.com/rumpelstiltzkin/jdk_locking_bug

根据记录的行为,我做错了什么,还是这是一个 JDK 错误?请注意,我不是要求其他方式来实现我的应用程序。


详细信息:这里有一些关于为什么我的应用程序正在做它正在做的事情的上下文。复制器代码是用于演示问题的精简版本。

我的应用程序有一个直写缓存。条目被插入到缓存中,并带有插入时间的时间戳,并且单独的刷新线程迭代缓存以查找在最后一次刷新线程将条目持久保存到磁盘之后创建的条目,即在 last-flush-time 之后。缓存只不过是一个 ConcurrentHashMap。

现在,可能会出现竞争,即使用时间戳 tX 构造条目,并且在将其插入 ConcurrentHashMap 时,刷新器线程迭代缓存并且找不到条目(它仍在插入,因此在刷新器中尚不可见-thread 的 Map::Iterator),因此它不会持久化它,并将最后一次刷新时间增加到 tY,使得 tY > tX。下次刷新线程迭代缓存时,它不会认为需要刷新 tX-timestamped 条目,我们将错过持久化它。最终 tX 将是一个非常旧的时间戳,缓存将永久删除它并丢失该更新。

为了解决这个问题,使用新条目更新缓存的线程在 lambda 中以 READ 模式获取 ReentrantReadWriteLock,该 lambda 在 ConcurrentHashMap::compute() 方法中构造缓存条目,并且刷新线程在 WRITE 模式下获取相同的 ReentrantReadWriteLock当抓住它的最后一次冲洗时间时。这确保了当刷新线程获取时间戳时,所有对象在 Map 中都是“可见的”,并且时间戳 <= 上次刷新时间。


在我的系统上复制:

所有线程(读取器和写入器)都阻塞等待 0x00000000c6511648

'top' 显示我的 java 进程已经休眠了几分钟(它逐渐使用一点点 CPU 来进行可能的上下文切换以及什么不是 - 请参阅 top 的手册页以获取更多解释为什么会发生这种情况)

0 投票
1 回答
500 浏览

java - Java 定时器 scheduleAtFixedRate。如何使调用 .cancel 仅在当前迭代完成后才停止计时器

我的应用程序中有一个 ReentrantReadWriteLock。在 timertask 的 run 方法中,我写了 lock 然后调用了一个函数。之后我解锁:

我担心的是如果这个计时器被取消并且锁无法解锁会发生什么。有没有办法使调用 .cancel 仅在当前迭代完成后才停止计时器。

或者是否有另一种数据结构可以让我在单独的线程上以一定的速率运行任务/函数并能够停止它以便释放所有锁?

0 投票
1 回答
241 浏览

java - ConcurrentHashMap 和 ReentrantReadWriteLock

我有一个更新数据的Map线程和几个读取这些数据的线程。现在我的代码如下所示:

但我认为我做得过火了。我只能ConcurrentHashMap在这种情况下使用吗?

0 投票
1 回答
79 浏览

kotlin - 在协程中使用包含 ReentrantReadWriteLock 的第三方代码

我正在使用在内部使用 ReentrantReadWriteLock 进行同步的第三方库。当然,库没有挂起功能。对于我的项目,我正在使用协程。使用带有协程挂起功能的库是否安全?