If methodA and methodB use different data structures, and it's safe to call methodA while somebody else is calling methodB, then those two methods should use different locks.
Here's the skinny on synchronized(XYZ.class)
synchronized (XYZ.class) is how you implment the above pattern -- it's a synchronized block that:
- acquires a lock on an object (in this class the instance of java.lang.class that represents XYZ)
- does some work
- releases the lock.
The key is to remember that every object in Java has a lock (the technical term is a monitor) that can be held by only one thread at a time. You can request the lock for any object that you have a reference to.
The synchronized keyword on a method:
public synchronized void foo() {
//do something
}
is just syntactic sugar for this:
public void foo() {
synchronized(this) {
//do something
}
}
There is one significant drawback to this approach: since anyone with a reference to an object can acquire its lock, synchronized methods won't work properly if an external caller acquires and holds the object lock.
(Incidentally, this is why locking on XYZ.class is also a bad idea: it's a globally accesible object, and you never know who might decide to acquire its lock)
To avoid these drawbacks, this pattern is usually used instead of the synchronized method:
private final Object LOCK = new Object();
public void foo() {
synchronized(LOCK) {
//do something
}
}
Since no external caller can have a reference to the LOCK object, only this class can acquire its lock, and the synchronized method will always work as expected.
When you have two different methods that need to be locked separately, the usual way to do that is for each method to lock on a different privately held object:
private final Object LOCKA = new Object();
private final Object LOCKB = new Object();
public void foo() {
synchronized(LOCKA) {
//do something
}
}
public void bar() {
synchronized(LOCKB) {
//do something else
}
}
Then it's possible for a thread to call foo() while another thread is calling bar(), but only one thread will be able to call foo() at a time, and only one thread will be able to call bar() at a time.