我有一个关键过程,我必须确保在任何时候都不能处理两个等效的MyObject(可以是不同的实例,但在逻辑上相等)。以下代码演示了这个想法:
public class MyClass {
public static ConcurrentMap<MyObject, String> concurrentMap = new ConcurrentHashMap<>();
public void process(MyObject myObject) {
String id = UUID.randomUUID().toString();
String existingId = concurrentMap.putIfAbsent(myObject, id);
synchronized (id) {
if (existingId == null) { // no others, start working right away
// do work
} else { // an equivalent myObject is under processing, wait on it
synchronized (existingId) {
// finally can start doing work
}
}
}
}
}
上面的代码在随机字符串的synchronized
的帮助下工作。但是这段代码的问题是
每次创建新的随机ID,但如果现有ID已链接到等效的MyObject,则不使用。这种id的唯一目的是充当由另一个线程发现的唯一锁。想一想这是否可以被一些实际的锁定对象取代?
这段代码中没有办法知道什么时候应该从concurrentMap中删除MyObject,虽然这不会影响结果,但如果concurrentMap保持增长可能不会很好。想在这里可以使用类似锁的计数器吗?
谢谢
答案 0 :(得分:2)
我不认为我真的理解这个想法的用例,这是一个大红旗。但在我看来,所有这些代码都是不必要的。如果此处唯一的想法是获取myObject
的唯一锁定,那么您已经拥有:myObject
。
public class MyClass {
public void process(MyObject myObject) {
synchronized (myObject) {
// finally can start doing work
}
}
}
剩下的代码就是自重。
然而,这仍然很充实。由于您依赖外部过程来同步对象,因此引用myObject
的任何其他代码都可以执行任何他们喜欢的操作,并且您无法控制它。这是一种非常弱的同步形式。它可以工作,如果代码库中的每个人都理解需要在MyObject
上进行同步,但这在实践中很难实现。
答案 1 :(得分:0)
我认为this库是您正在寻找的。特别是StripedKeyLockManager和CountingLock课程可以解决您的问题。您可以在项目中使用库,也可以根据需要调整源代码。 Guava还通过Stripped类提供类似的功能。