问题
While I am going though few Java Thread tutorials I got to the following statement.
It's a good practice to have separate lock objects instead of having clock on object that get modified in the synchronized block. Java underlying code optimization may create implications.
What does it exactly stating?
Say I have code as follows to imply the situation.
public class TestSynch(){
private Object lock1;
private Object lock2;
private List<Integer> list1;
private List<Integer> list2;
public void doListOne(){
synchronized(lock1){
// some server processing
list1.add(/*some random number using random generator*/);
}
}
public void doListTwo(){
synchronized(lock1){
// some server processing
list2.add(/*some random number using random generator*/);
}
}
}
Say I have some method calling the above two methods sequentially in a loop and that method is being called by two different threads.
What would be implication with respect to Java code optimization if I use list1 and list2 instead of lock1 and lock2?
回答1:
There may be reasons for having a separate object(s) for locking. For example, when the object, guarded, may be null, or when there are different ways to modify it, that do not need to be synchronized with each other, or if the object, being guarded is accessible (read-only) by code outside your api (you don't want to be affected if someone decides to synchronize on it).
But in general, if none of these applies or is a concern, there is nothing wrong with synchronizing on the object that's being modified. I have no idea what "implications" the excerpt you quoted is talking about.
Note, that synchronization in general may not be the best approach to begin with. Take a look at the *Lock classes, provided by java.util.concurrent package. You might want to use one of those, as they provide greater flexibility is features you cannot accomplish with synchronizing, such as fairness or sharing.
回答2:
What would be implication with respect to Java code optimization if I use list1 and list2 instead of lock1 and lock2?
It's not about optimization, it's about encapsulation.
In your example, there would be no practical difference between synchronizing on the list objects vs. synchronizing on separate lock objects.
The normal use-case for a private lock-object is when the class functions as a monitor. The classic implementation of a monitor looks like this:
class MyMonitor {
synchronized foo(...) { ... }
synchronized bar(...) { ... }
synchronized baz(...) { ... }
}
The private-lock way of doing the same thing looks like
class MyMonitor {
private Object lock = new Object();
foo(...) { synchronized(lock) { ... } }
bar(...) { synchronized(lock) { ... } }
baz(...) { synchronized(lock) { ... } }
}
The "problem" with doing it the classic way is that the client of the MyMonitor class potentially could use a MyMonitor instance to synchronize something else:
MyMonitor myMonitor = ...;
synchronized( myMonitor ) { ... }
Why would anybody ever write that? I have no idea. But if somebody did, then the client's use of a myMonitor object as a lock could interfere with the MyMonitor class's use of the same object as a lock.
The second way, using the private lock object, insures that even if the client does use a MyMonitor for locking something else, it can't possibly interfere with the MyMonitor instance's private lock.
None of this really applies to your example, because in your example the lists are private variables that (presumably) are not visible to clients.
来源:https://stackoverflow.com/questions/27677501/why-is-it-a-good-practice-to-have-separate-locks-instead-of-having-lock-on-objec