Whenever a question pops up on SO about Java synchronization, some people are very eager to point out that synchronized(this)
should be avoided. Instead, they claim, a lock on a private reference is to be preferred.
Some of the given reasons are:
- some evil code may steal your lock (very popular this one, also has an "accidentally" variant)
- all synchronized methods within the same class use the exact same lock, which reduces throughput
- you are (unnecessarily) exposing too much information
Other people, including me, argue that synchronized(this)
is an idiom that is used a lot (also in Java libraries), is safe and well understood. It should not be avoided because you have a bug and you don't have a clue of what is going on in your multithreaded program. In other words: if it is applicable, then use it.
I am interested in seeing some real-world examples (no foobar stuff) where avoiding a lock on this
is preferable when synchronized(this)
would also do the job.
Therefore: should you always avoid synchronized(this)
and replace it with a lock on a private reference?
Some further info (updated as answers are given):
- we are talking about instance synchronization
- both implicit (
synchronized
methods) and explicit form ofsynchronized(this)
are considered - if you quote Bloch or other authorities on the subject, don't leave out the parts you don't like (e.g. Effective Java, item on Thread Safety: Typically it is the lock on the instance itself, but there are exceptions.)
- if you need granularity in your locking other than
synchronized(this)
provides, thensynchronized(this)
is not applicable so that's not the issue
I think points one (somebody else using your lock) and two (all methods using the same lock needlessly) can happen in any fairly large application. Especially when there's no good communication between developers.
It's not cast in stone, it's mostly an issue of good practice and preventing errors.
A lock is used for either visibility or for protecting some data from concurrent modification which may lead to race.
When you need to just make primitive type operations to be atomic there are available options like
AtomicInteger
and the likes.But suppose you have two integers which are related to each other like
x
andy
co-ordinates, which are related to each other and should be changed in an atomic manner. Then you would protect them using a same lock.A lock should only protect the state that is related to each other. No less and no more. If you use
synchronized(this)
in each method then even if the state of the class is unrelated all the threads will face contention even if updating unrelated state.In the above example I have only one method which mutates both
x
andy
and not two different methods asx
andy
are related and if I had given two different methods for mutatingx
andy
separately then it would not have been thread safe.This example is just to demonstrate and not necessarily the way it should be implemented. The best way to do it would be to make it IMMUTABLE.
Now in opposition to
Point
example, there is an example ofTwoCounters
already provided by @Andreas where the state which is being protected by two different locks as the state is unrelated to each other.The process of using different locks to protect unrelated states is called Lock Striping or Lock Splitting
While I agree about not adhering blindly to dogmatic rules, does the "lock stealing" scenario seem so eccentric to you? A thread could indeed acquire the lock on your object "externally"(
synchronized(theObject) {...}
), blocking other threads waiting on synchronized instance methods.If you don't believe in malicious code, consider that this code could come from third parties (for instance if you develop some sort of application server).
The "accidental" version seems less likely, but as they say, "make something idiot-proof and someone will invent a better idiot".
So I agree with the it-depends-on-what-the-class-does school of thought.
Edit following eljenso's first 3 comments:
I've never experienced the lock stealing problem but here is an imaginary scenario:
Let's say your system is a servlet container, and the object we're considering is the
ServletContext
implementation. ItsgetAttribute
method must be thread-safe, as context attributes are shared data; so you declare it assynchronized
. Let's also imagine that you provide a public hosting service based on your container implementation.I'm your customer and deploy my "good" servlet on your site. It happens that my code contains a call to
getAttribute
.A hacker, disguised as another customer, deploys his malicious servlet on your site. It contains the following code in the
init
method:Assuming we share the same servlet context (allowed by the spec as long as the two servlets are on the same virtual host), my call on
getAttribute
is locked forever. The hacker has achieved a DoS on my servlet.This attack is not possible if
getAttribute
is synchronized on a private lock, because 3rd-party code cannot acquire this lock.I admit that the example is contrived and an oversimplistic view of how a servlet container works, but IMHO it proves the point.
So I would make my design choice based on security consideration: will I have complete control over the code that has access to the instances? What would be the consequence of a thread's holding a lock on an instance indefinitely?
If you've decided that:
then I don't see the a taboo over synchronizezd(this).
Some people deliberately use synchronized(this) (instead of marking the method synchronized) inside the whole contents of a method because they think it's "clearer to the reader" which object is actually being synchronized on. So long as people are making an informed choice (e.g. understand that by doing so they're actually inserting extra bytecodes into the method and this could have a knock-on effect on potential optimisations), I don't particularly see a problem with this. You should always document the concurrent behaviour of your program, so I don't see the "'synchronized' publishes the behaviour" argument as being so compelling.
As to the question of which object's lock you should use, I think there's nothing wrong with synchronizing on the current object if this would be expected by the logic of what you're doing and how your class would typically be used. For example, with a collection, the object that you would logically expect to lock is generally the collection itself.
There seems a different consensus in the C# and Java camps on this. The majority of Java code I have seen uses:
whereas the majority of C# code opts for the arguably safer:
The C# idiom is certainly safer. As mentioned previously, no malicious / accidental access to the lock can be made from outside the instance. Java code has this risk too, but it seems that the Java community has gravitated over time to the slightly less safe, but slightly more terse version.
That's not meant as a dig against Java, just a reflection of my experience working on both languages.
Short answer: You have to understand the difference and make choice depending on the code.
Long answer: In general I would rather try to avoid synchronize(this) to reduce contention but private locks add complexity you have to be aware of. So use the right synchronization for the right job. If you are not so experienced with multi-threaded programming I would rather stick to instance locking and read up on this topic. (That said: just using synchronize(this) does not automatically make your class fully thread-safe.) This is a not an easy topic but once you get used to it, the answer whether to use synchronize(this) or not comes naturally.