gpt4 book ai didi

java - 有没有办法在 Java 中使用两个锁对象进行同步?

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:15:38 25 4
gpt4 key购买 nike

我想知道 Java 中是否有一种方法可以使用两个锁对象进行同步。我的意思不是锁定任一个对象,我的意思是只锁定两者

例如如果我有 4 个线程:

  • 线程 A 使用 Object1 和 Object2 请求锁
  • 线程 B 使用 Object1 和 Object3 请求锁
  • 线程 C 使用 Object4 和 Object2 请求锁
  • 线程 D 使用 Object1 和 Object2 请求锁

在上面的场景中,线程 A 和线程 D 将共享一个锁,但线程 B 和线程 C 将拥有自己的锁。即使它们与两个对象之一重叠,相同的锁也仅在两个对象重叠时才适用。

所以我有一个由许多线程调用的方法,它将根据特定的数据库执行特定的 Activity 类型。我有数据库和 Activity 的标识符对象,我可以保证该操作是线程安全的,只要它不是基于与另一个线程相同的数据库的相同 Activity 。

我理想的代码应该是这样的:

public void doActivity(DatabaseIdentifier dbID, ActivityIdentifier actID) {    
synchronized( dbID, actID ) { // <--- Not real Java
// Do an action that can be guaranteed thread-safe per unique
// combination of dbIT and actID, but needs to share a
// lock if they are both the same.
}
}

我可以创建由 DatabaseIdentifier 和 ActivityIdentifier 键控的锁对象的散列映射,但是当我需要以线程安全的方式创建/访问这些锁时,我将遇到相同的同步问题。

现在我只是在 DatabaseIdentifier 上进行同步。一个 DBIdentifier 同时进行多项 Activity 的可能性要小得多,因此我很少会过度锁定。 (虽然不能说相反的方向相同。)

有没有人有解决这个问题的好方法而不涉及强制不必要的线程等待?

谢谢!

最佳答案

让每个 DatabaseIdentifier 保留一组锁定到它拥有的 ActivityIdentifier 的锁

所以你可以调用

public void doActivity(DatabaseIdentifier dbID, ActivityIdentifier actID) {    
synchronized( dbID.getLock(actID) ) {
// Do an action that can be guaranteed thread-safe per unique
// combination of dbIT and actID, but needs to share a
// lock if they are both the same.
}
}

那么你只需要在 dbID 中对底层集合(使用 ConcurrentHashMap)进行(短)锁

换句话说

ConcurrentHashMap<ActivityIdentifier ,Object> locks = new...
public Object getLock(ActivityIdentifier actID){
Object res = locks.get(actID); //avoid unnecessary allocations of Object

if(res==null) {
Object newLock = new Object();
res = locks.puIfAbsent(actID,newLock );
return res!=null?res:newLock;
} else return res;
}

这比锁定 dbID 上的完整操作要好(尤其是当它是一个长操作时),但仍然比您的理想场景差

更新以回应关于 EnumMap 的评论

private final EnumMap<ActivityIdentifier ,Object> locks;

/**
initializer ensuring all values are initialized
*/
{
EnumMap<ActivityIdentifier ,Object> tmp = new EnumMap<ActivityIdentifier ,Object>(ActivityIdentifier.class)
for(ActivityIdentifier e;ActivityIdentifier.values()){
tmp.put(e,new Object());
}
locks = Collections.unmodifiableMap(tmp);//read-only view ensures no modifications will happen after it is initialized making this thread-safe
}


public Object getLock(ActivityIdentifier actID){
return locks.get(actID);
}

关于java - 有没有办法在 Java 中使用两个锁对象进行同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7985971/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com