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
It depends on the situation.
If There is only one sharing entity or more than one.
See full working example here
A small introduction.
Threads and shareable entities
It is possible for multiple threads to access same entity, for eg multiple connectionThreads sharing a single messageQueue. Since the threads run concurrently there may be a chance of overriding one's data by another which may be a messed up situation.
So we need some way to ensure that shareable entity is accessed only by one thread at a time. (CONCURRENCY).
Synchronized block
synchronized() block is a way to ensure concurrent access of shareable entity.
First, a small analogy
Suppose There are two-person P1, P2 (threads) a Washbasin (shareable entity) inside a washroom and there is a door (lock).
Now we want one person to use washbasin at a time.
An approach is to lock the door by P1 when the door is locked P2 waits until p1 completes his work
P1 unlocks the door
then only p1 can use washbasin.
syntax.
"this" provided the intrinsic lock associated with the class (Java developer designed Object class in such a way that each object can work as monitor). Above approach works fine when there are only one shared entity and multiple threads (1: N).
N shareable entities-M threads
Now think of a situation when there is two washbasin inside a washroom and only one door. If we are using the previous approach, only p1 can use one washbasin at a time while p2 will wait outside. It is wastage of resource as no one is using B2 (washbasin).
A wiser approach would be to create a smaller room inside washroom and provide them one door per washbasin. In this way, P1 can access B1 and P2 can access B2 and vice-versa.
See more on Threads----> here
This is really just supplementary to the other answers, but if your main objection to using private objects for locking is that it clutters your class with fields that are not related to the business logic then Project Lombok has
@Synchronized
to generate the boilerplate at compile-time:compiles to