I’m wondering if there’s a way in Java to synchronize using two lock objects.
I don’t mean locking on either object, I mean locking only on both.
e.g. if I have 4 threads:
- Thread A requests a lock using Object1 and Object2
- Thread B requests a lock using Object1 and Object3
- Thread C requests a lock using Object4 and Object2
- Thread D requests a lock using Object1 and Object2
In the above scenario, Thread A and Thread D would share a lock, but Thread B and Thread C would have their own locks. Even though they overlap with one of the two objects, the same lock only applies if it overlaps on both.
So I have a method called by many threads which is going to perform a specific activity type based on a specific database. I have identifier objects for both the database and the activity, and I can guarantee that the action will be thread safe as long as it is not the same activity based on the same database as another thread.
My ideal code would look something like:
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.
}
}
I could create a hashmap of lock objects that are keyed by both the DatabaseIdentifier and the ActivityIdentifier, but I’m going to run into the same synchronization issue when I need to create/access those locks in a thread-safe way.
For now I’m just synchronizing on the DatabaseIdentifier. It’s much less likely that there will be multiple activities going on at the same time for one DBIdentifier, so I will only rarely be over-locking. (Can’t say the same for the opposite direction though.)
Anyone have a good way to handle this that doesn’t involve forcing unnecessary threads to wait?
Thanks!
have each
DatabaseIdentifierkeep a set of locks keyed toActivityIdentifiers that it ownsso you can call
then you only need a (short) lock on the underlying collection (use a ConcurrentHashMap) in
dbIDin other words
this is better than locking the full action on dbID (especially when its a long action) but still worse than your ideal scenario
update in responce to comments about EnumMap