5
2
|
Let's say we have very simple Java class
MyClass .
There are three ways to construct thread-safe Java class which has some state:
There is one more fact that should be added to the context of discussion. In a multhithreaded environment JVM is free to reorder instructions outside of
synchronized block preserving a logical sequence and happens-before relationships specified by JVM. It may cause publishing object which is not properly constructed yet to another thread.
I've got a couple of questions regarding the third case.
This strange-looking
synchronized (new Object()) is supposed to prevent reordering effect. Will it work?
Just to be clear, all these examples don't have any practical applications. I'm just curious about nuances of multithreading.
| ||
add comment |
3
| synchronized(new Object()) will do nothing, since synchronization is only on the object you synchronize on. So if thread A synchronizes on oneObject , and thread B synchronizes onanotherObject , there is no happens-before between them. Since we can know for a fact that no other thread will ever synchronize on the new Object() you create there, this won't establish a happens-before between any other thread.
Regarding your
synchronzied in the constructor, if your object is safely published to another thread, you don't need it; and if it's not, you're probably in a mess of trouble as it is. I asked this question on the concurrency-interest list a bit ago, and an interesting thread resulted. See in particular this email, which points out that even with your constructor synchronized, in the absence of safe publication another thread could see default values in your fields, and this email which (imho) ties the whole thing together. | |||
add comment |
2
|
In question #3,
synchronized(new Object()) is a no-op and will prevent nothing. The compiler can determine that no other threads could possibly synchronize on that object (since nothing else can access the object.) This is an explicit example in Brian Goetz's paper "Java theory and practice: Synchronization optimizations in Mustang".
Even if you did need to synchronize in a constructor, and even if your
synchronized(new Object()) block was useful - ie, you were synchronizing on a different long-lived object, since your other methods are synchronizing on this , you have visibility problems if you're not synchronizing on the same variable. That is to say, you do indeed want your constructor to also use synchronized(this) .
An aside:
Synchronizing on
this is considered poor form. Instead, synchronize on some private final field. Callers may synchronize on your object, which could lead to a deadlock. Consider the following:
It's not obvious to callers of the
Foo class that this would deadlock. Best to keep your locking semantics internal and private to your class. | ||||||||||||||||||||
|
A, B, C
(where for instance,A
is the sync,B
is the field assignment,C
is setting the reference afternew
), thread B is allowed to seeC A B
if there's no happens-before edge -- whichsynchronized(new Object())
will never provided. For instance, if thread B is on a different core,C
could get flushed beforeA
. – yshavit Mar 8 '12 at 18:58