可以从一个线程转移到另一个线程的锁
我正在寻找一种锁,其中持有锁的线程可以将其传递给它选择的另一个线程。
这就是我想要它的原因:
- 我有一个类似于ConcurrentHashMap的类 - 一个分为多个段的专门集合
- 大多数修改只需要锁定一个段。少数需要锁定两个段(具体来说,修改一个键,以便它从一个段移动到另一个段。)
- 大多数读取不需要锁定 - 易失性读取通常就足够了,但有时搜索需要一次锁定所有段,如果修改计数检查失败
- 搜索是在多个线程中完成的(通过 ThreadPoolExecutor )
- 搜索函数必须对所有段具有一致的视图(例如,在搜索时不得错过任何条目)正在从一个段移动到另一个段。)
- 搜索任务(针对单个段)可能随时中断。
现在我正在考虑这样的情况:在主线程中调用了search方法,发现它需要锁定所有段。所有段锁必须由主线程立即持有(以确保没有干扰),但执行更新的不是主线程 - 它是工作线程之一。因此,我试图让主线程在知道它具有一致的快照后“传递”锁。
我们曾经对整个集合使用单个锁,但随着它变得越来越大,小更新就会出现太多的争用和令人无法接受的高延迟。
解锁和重新锁定(在 ReentrantLock 上)并不安全 - 另一个线程可能会在工作线程开始搜索之前修改该段。
普通的信号量可以处理不同线程的锁定和解锁。接下来出现的问题是谁应该释放信号量 - 工作线程需要一种方法来表明它已经获得了锁的所有权(因为它可能会在此点之前或之后抛出异常,并且主线程需要知道是否要清理) )单元测试也很棘手,因为你永远不知道信号量获取或释放是否发生在正确的线程中。
如果锁可以在其他方法中可重入使用(不在线程之间传递),那将是一个额外的好处。
我想象 Semaphore
和 AtomicBoolean
的某种组合或需要 AtomicReference
,但快速的谷歌搜索没有显示任何示例。有什么理由不应该使用这种方法?
I am looking for a type of lock where the thread that holds the lock can pass it on to another thread of its choosing.
Here is why I want it:
- I have a class similar to
ConcurrentHashMap
- a specialized collection that is divided into multiple segments - Most modifications require only one segment to be locked. A few require two segments to be locked (specifically, modifying a key so that it moves from one segment to another.)
- Most reads do not require locking - a volatile read is usually sufficient, but occasionally a search needs to lock all segments at once, if a modification-count check fails
- Searching is done in multiple threads (via a
ThreadPoolExecutor
) - It is essential that the search function has a consistent view of all segments (e.g. it must not miss an entry while it is being moved from one segment to another.)
- The search task (for a single segment) may be interrupted at any time.
Now I am considering the situation where the search method has been called in the main thread and discovers it needs to lock all segments. All of the segment locks must be held at once by the main thread (to ensure there is no interference) but it is not the main thread that will be doing the updates - it is one of the worker threads. Hence I am trying to make the main thread "pass on" the locks once it knows it has a consistent snapshot.
We used to use a single lock for the whole collection but as it got larger there was too much contention and unacceptably high latency for small updates.
Unlocking and re-locking (on a ReentrantLock
) is not safe - another thread may modify the segment before the worker thread starts the search.
A plain Semaphore
can handle locking and unlocking by different threads. The issue that then arises is who should release the semaphore - the worker thread needs a way to signal that it has taken ownership of the lock (because it may throw an exception before or after this point and the main thread needs to know whether to clean up.) It would also be tricky to unit-test because you never know if a semaphore acquire or release has occurred in the correct thread.
It would be a bonus if the lock could be used reentrantly in other methods (where it is not passed between threads.)
I imagine some combination of a Semaphore
and an AtomicBoolean
or AtomicReference
is called for, but a quick google search did not reveal any examples. Is there any reason why this approach should not be used?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
读/写锁的反向使用可能会起作用。在这个习惯用法中,读锁持有者对数据结构(例如数组中的独立槽)执行并发写入。写锁用于获取独占访问权限以执行一致的读取(例如对数组求和)。这是一个很少使用的习语,但在那些奇怪的情况下很优雅。你的问题有点难以理解,但这至少可以为具体的解决方案提供一些灵感。我怀疑,通过更深入的理解,问题可以被简化,从而使经典解决方案更合适。
An inverted use of a read/write lock may work. In this idiom, the read lock holders perform concurrent writes to the data structure (e.g. independent slots in an array). The write lock is used to acquire exclusive access to perform a consistent read (e.g. summing the array). This is a rarely used idiom, but elegant in those oddball cases. Your problem is a bit hard to grok, but this may at least offer some inspiration for a concrete solution. I suspect with a deeper understanding, the problem could be simplified so that a classical solution is more appropriate.