Reputation: 10531
For instance,
class Test{
static Map a = new ...
static Map b = new ...
public void process(){
...
a.put(...);
b.put(...);
}
}
Do I have to lock like this:
synchronized(a){
a.put();
}
synchronized(b){
b.put(b);
}
This seems to be awkward. Any other right way to do this? Thanks.
Upvotes: 1
Views: 1224
Reputation: 2790
You can use a dedicated object like
Object mapLock = new Object();
to synchronize on.
Or you can sync on a
keeping in mind that even if you need an access to b
you need to sync on a
.
Synchronizing on this
is not a good idea in general. I mean this is a bad habit and doing so may eventually result in bad performance or non-obvious deadlocks if not in this but other applications you make.
Avoid synchronized(this) in Java?
You can also consider using ReadWriteLock from concurrency package.
Upvotes: 1
Reputation: 606
You do need to run both operations within one synchronized
block. Worth noting that in your example, you've defined the maps statically while the process()
method is an instance method. The synchronizing the method will mean that calls to that instance will be synchronized, but that calls to 2 different instances will not (as the lock used when applying the synchronized keyword to a method is effectively this
). You could either make the process() method static, or use a synchronized(Test.class) {}
block instead to ensure that there's no racing happening.
You will also need to be careful about how you expose the maps to clients - if you're offering them up as properties, then I would probably wrap them with Collections.unmodifiableMap() to ensure that nothing else can go and screw with them while you're not looking - however that doesn't entirely protect against clients having an "odd" time as they will still see changes happen in potentially unsafe ways. As such, I'd also probably declare the types as ConcurrentHashMap to make things a little safer (although there are still some dangerous operations such as sharing an Iterator between threads)
Upvotes: 0
Reputation: 10831
No, you need both operations in one synchronized
block, otherwise another thread may see inconsistencies between the two maps.
One possible option would be using a synchronized
method, or you could use some other private object or one of the maps as an monitor. Here is the synchronized method example:
static Map a = new ...
static Map b = new ...
public synchronized void process(){
...
a.put(...);
b.put(...);
}
}
Upvotes: 2