【发布时间】:2011-01-27 06:35:36
【问题描述】:
我正在寻找一种锁,持有锁的线程可以将其传递给它选择的另一个线程。
这就是我想要它的原因:
- 我有一个类似于
ConcurrentHashMap的类 - 一个专门的集合,分为多个段 - 大多数修改只需要锁定一个段。少数需要锁定两个段(特别是修改一个键,使其从一个段移动到另一个段。)
- 大多数读取不需要锁定 - 易失性读取通常就足够了,但有时如果修改计数检查失败,搜索需要一次锁定所有段
- 搜索在多个线程中完成(通过
ThreadPoolExecutor) - 搜索功能必须对所有片段具有一致的视图(例如,在从一个片段移动到另一个片段时,它不能错过一个条目。)
- 搜索任务(针对单个片段)可能随时中断。
现在我正在考虑在主线程中调用搜索方法并发现它需要锁定所有段的情况。所有的段锁必须由主线程一次持有(以确保没有干扰),但不是主线程将进行更新 - 它是工作线程之一。因此,一旦主线程知道它具有一致的快照,我就会尝试让主线程“传递”锁。
我们过去对整个集合使用单个锁,但随着它变得越来越大,争用太多,小更新的延迟高到无法接受。
解锁和重新锁定(在ReentrantLock 上)不安全 - 另一个线程可能会在工作线程开始搜索之前修改该段。
普通的Semaphore 可以处理不同线程的锁定和解锁。然后出现的问题是谁应该释放信号量 - 工作线程需要一种方法来表明它已经获得了锁的所有权(因为它可能会在此之前或之后抛出异常,并且主线程需要知道是否要清理up.) 单元测试也很棘手,因为您永远不知道信号量获取或释放是否发生在正确的线程中。
如果锁可以在其他方法中可重入使用(在线程之间不传递),那将是一个好处。
我想Semaphore 和AtomicBoolean 或AtomicReference 的某种组合是需要的,但快速谷歌搜索没有发现任何示例。有什么理由不应该使用这种方法吗?
【问题讨论】:
-
并发最适合简单模型。鉴于您的描述的长度和模型的复杂性,我建议您尝试简化您的要求。恕我直言,它更有可能有效地工作。我知道唤醒特定线程的唯一方法是 Unsafe.park() 和 Unsafe.unpark(Thread) 但我不建议直接使用它们。
-
如果你想要的只是一个可以传递的“锁”,为什么不使用令牌传递机制,将每个段锁作为一个令牌,并按字面意思传递呢?如果集合搜索时间足够长,这个令牌甚至可以是一个文件,文件充当锁。主线程可以简单地将“锁”给工作线程。
-
是否可以通过具有关联“更新”的持久结构创建新结构而不是就地修改来以无锁方式建模?您的描述是一种解决方案,而不是您要解决的根本问题,因此很难提出建议。
标签: java concurrency locking atomic semaphore