synchronized on construction

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

synchronized on construction

Jason Mehrens
Browsing over the java.util.Vector class I noticed that in the constructors,
the initial writes to the internal data members (non-final and non-volatile)
are not performed under a synchronized block.   The same is true for when a
Vector is deserialized.  Where does happens-before edge occur so that other
threads don't see uninitialized values of the internals?  The only happens
before-edges I can think of are during handoff between threads or on the
call to Thread.start().  Is how this class conforms to the JMM or is
something else going on?

Thanks,

Jason Mehrens


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Jeremy Manson
Jason Mehrens wrote:
> Browsing over the java.util.Vector class I noticed that in the constructors,
> the initial writes to the internal data members (non-final and non-volatile)
> are not performed under a synchronized block.   The same is true for when a
> Vector is deserialized.  Where does happens-before edge occur so that other
> threads don't see uninitialized values of the internals?  The only happens
> before-edges I can think of are during handoff between threads or on the
> call to Thread.start().  Is how this class conforms to the JMM or is
> something else going on?
>

Well, bear in mind that only one thread has access to instances of these
classes during construction.  JMM problems only come up here if you pass
a reference to the object to another thread via a data race.  These
classes are not designed to work correctly if you do that - only the
immutable ones, like String, really are.

If you are using this class, it is therefore imperative to provide
proper synchronization during a handoff.

This is one of the reasons why people have moved away from Vector and
Hashtable -- by claiming that they are thread-safe, they make people
stop worrying about multithreaded behavior.  However, their guarantees
are illusory - if you examine them too closely, they melt away...

                                        Jeremy
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Thomas Hawtin
Jeremy Manson wrote:
> Jason Mehrens wrote:
>> Browsing over the java.util.Vector class I noticed that in the constructors,
>> the initial writes to the internal data members (non-final and non-volatile)
>> are not performed under a synchronized block.   The same is true for when a

Under the new JMM would a synchronised block in the constructor
guarantee to fix the problem? Does the racy write of the Vector
reference, outside of the synchronised block, necessarily come after the
block itself. Could it technically be moved up before the lock is
acquired? Or am I misinterpreting something?

>> Vector is deserialized.  Where does happens-before edge occur so that other
>> threads don't see uninitialized values of the internals?  The only happens
>> before-edges I can think of are during handoff between threads or on the
>> call to Thread.start().  Is how this class conforms to the JMM or is
>> something else going on?
>>
>
> Well, bear in mind that only one thread has access to instances of these
> classes during construction.  JMM problems only come up here if you pass
> a reference to the object to another thread via a data race.  These
> classes are not designed to work correctly if you do that - only the
> immutable ones, like String, really are.
>
> If you are using this class, it is therefore imperative to provide
> proper synchronization during a handoff.

Bug 6379897 deals with the thread safety of Random's seed when
constructed lazily in Collections. It's interested to see that the fix
for that attempts to make the use of seed thread-safe, rather than
construct the Random safely in Collections. Presumably the details of
that fix (setting of the seed value) require that my first paragraph is
wrong...

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6379897

Tom Hawtin
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Pete.Soper
Thomas Hawtin wrote:

> Jeremy Manson wrote:
>
>>Jason Mehrens wrote:
>>
>>>Browsing over the java.util.Vector class I noticed that in the constructors,
>>>the initial writes to the internal data members (non-final and non-volatile)
>>>are not performed under a synchronized block.   The same is true for when a
>
>
> Under the new JMM would a synchronised block in the constructor
> guarantee to fix the problem? Does the racy write of the Vector
> reference, outside of the synchronised block, necessarily come after the
> block itself. Could it technically be moved up before the lock is
> acquired? Or am I misinterpreting something?
>
>
>>>Vector is deserialized.  Where does happens-before edge occur so that other
>>>threads don't see uninitialized values of the internals?  The only happens
>>>before-edges I can think of are during handoff between threads or on the
>>>call to Thread.start().  Is how this class conforms to the JMM or is
>>>something else going on?
>>>
>>
>>Well, bear in mind that only one thread has access to instances of these
>>classes during construction.  JMM problems only come up here if you pass
>>a reference to the object to another thread via a data race.  These
>>classes are not designed to work correctly if you do that - only the
>>immutable ones, like String, really are.
>>
>>If you are using this class, it is therefore imperative to provide
>>proper synchronization during a handoff.
>
>
> Bug 6379897 deals with the thread safety of Random's seed when
> constructed lazily in Collections. It's interested to see that the fix
> for that attempts to make the use of seed thread-safe, rather than
> construct the Random safely in Collections. Presumably the details of
> that fix (setting of the seed value) require that my first paragraph is
> wrong...
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6379897

There is a special guarantee extended to final fields related to
construction that the experts can explain better than me. And as far as
I can tell there is no possibility of "this" being published before the
constructor completes. So this (current Mustang source for) Random looks
looks OK and I think the attempt was successful.

-Pete

>
> Tom Hawtin
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
>

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Jeremy Manson
In reply to this post by Thomas Hawtin
Thomas Hawtin wrote:
> Under the new JMM would a synchronised block in the constructor
> guarantee to fix the problem? Does the racy write of the Vector
> reference, outside of the synchronised block, necessarily come after the
> block itself. Could it technically be moved up before the lock is
> acquired? Or am I misinterpreting something?
>

The system will not move the racy write up before the lock is acquired,
although it may move it inside the synchronization block.  We have
"Roach Motel Semantics" - you can move the write up into the
synchronization block, but you can't move it out of that block.

The reason for this has to do with locking and happens-before, and I
shall leave it as an exercise to the reader ;) .

I want to reiterate my previous statement.  If you are using this class,
you have to use synchronization to ensure that the reference to the
object gets communicated between threads *at all*.  As long as you are
doing this, the happens-before relationship will be present, so you are
safe.

If you don't have that synchronization in your code, then there you have
a bug.  A data race.  Data races rot the brain and corrupt the soul.

> Bug 6379897 deals with the thread safety of Random's seed when
> constructed lazily in Collections. It's interested to see that the fix
> for that attempts to make the use of seed thread-safe, rather than
> construct the Random safely in Collections. Presumably the details of
> that fix (setting of the seed value) require that my first paragraph is
> wrong...
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6379897

This bug discusses making the seed final, which ends up being a separate
issue from the one in your first paragraph.  Declaring a field final
means that the correctly constructed value will be visible to threads
that see a reference to that object, even if you have no additional
synchronization.  It is an excellent way to provide thread-safe
initialization, as long as your field doesn't change.  This cannot be
done for the fields of Vector, though, because its fields can be changed.

The final modifier is a good one in general, and, like "private", should
be used wherever possible.  A caution: final field guarantees are only
made to threads that do not see, via a data race, a reference to the
object that was written in the constructor.

The bug has this comment:

> The submitter is correct (according to the Java Memory Model).
> However, we can't seem to make these bugs actually manifest in the wild.
> We would love an actual test on the Sun JDK that demonstrates the failure
> (even if only once in a million tries).

Maybe it doesn't happen on their testbed, but wait until someone makes
that one tweak to the VM and tries to run the code on 384 processors...

                                        Jeremy
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Thomas Hawtin
Jeremy Manson wrote:

> Thomas Hawtin wrote:
>> Under the new JMM would a synchronised block in the constructor
>> guarantee to fix the problem? Does the racy write of the Vector
>> reference, outside of the synchronised block, necessarily come after
>> the block itself. Could it technically be moved up before the lock is
>> acquired? Or am I misinterpreting something?
>>
>
> The system will not move the racy write up before the lock is acquired,
> although it may move it inside the synchronization block.  We have
> "Roach Motel Semantics" - you can move the write up into the
> synchronization block, but you can't move it out of that block.
>
> The reason for this has to do with locking and happens-before, and I
> shall leave it as an exercise to the reader ;) .

So, in this situation, as a reader...

Suppose we have thread t that creates an object with a synchronised
block in the constructor and thread u that uses that object under
synchronisation.

Suppose further, for the sake of contradiction, that the lock in u
occurs earlier in the synchronisation order than t. The read of the
object reference in u must happen-before it uses the lock. The use of
the lock in t must happen-before the write of the object reference.
Therefore the read of the reference in u must happen-before the write of
the reference in t, so will have an old value.

Is that vaguely right?

> If you don't have that synchronization in your code, then there you have
> a bug.  A data race.  Data races rot the brain and corrupt the soul.

Yeah but my soul is already corrupt and my brain nicely folded.

> This bug discusses making the seed final, which ends up being a separate
> issue from the one in your first paragraph.  Declaring a field final
> means that the correctly constructed value will be visible to threads
> that see a reference to that object, even if you have no additional
> synchronization.  It is an excellent way to provide thread-safe
> initialization, as long as your field doesn't change.  This cannot be
> done for the fields of Vector, though, because its fields can be changed.

It wasn't the reference I was worried about, but the resetting of the
seed after the final field is assigned. Even ignoring the above, it's
still fine because the freeze happens at the end of the constructor, not
at the assignment.

Tom Hawtin
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Jeremy Manson
Thomas Hawtin wrote:

> Jeremy Manson wrote:
>> The system will not move the racy write up before the lock is acquired,
>> although it may move it inside the synchronization block.  We have
>> "Roach Motel Semantics" - you can move the write up into the
>> synchronization block, but you can't move it out of that block.
>>
>> The reason for this has to do with locking and happens-before, and I
>> shall leave it as an exercise to the reader ;) .
>
> So, in this situation, as a reader...
>
> Suppose we have thread t that creates an object with a synchronised
> block in the constructor and thread u that uses that object under
> synchronisation.
>
> Suppose further, for the sake of contradiction, that the lock in u
> occurs earlier in the synchronisation order than t. The read of the
> object reference in u must happen-before it uses the lock. The use of
> the lock in t must happen-before the write of the object reference.
> Therefore the read of the reference in u must happen-before the write of
> the reference in t, so will have an old value.
>
> Is that vaguely right?
>

It is along the right lines.  The best way to think about it is to
consider two, more generic locking regions:

Thread 1:
synchronized (o) {
   r1 = x;
   r2 = y;
}

Thread 2:
synchronized (o) {
   y = 1;
}
x = 1;

Let's say that Thread 1's synchronized block happens-before Thread 2's.
  Then both reads in Thread 1 are guaranteed to see the value 0 (because
the reads happen-before the write in Thread 2).

If you move the write to x _inside_ the locking region, the read will
still not see the value 1, because the read of x will still
happen-before the write to x.

However, if you move the write to x to _before_ the locking region, then
the read of x might see the value 1.  Since the read of x happens-before
the write to x, the system can't do this.

>> If you don't have that synchronization in your code, then there you have
>> a bug.  A data race.  Data races rot the brain and corrupt the soul.
>
> Yeah but my soul is already corrupt and my brain nicely folded.

... and I'm sure your clients appreciate when that comes out in your code!

                                        Jeremy
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Thomas Hawtin
Jeremy Manson wrote:

> Thomas Hawtin wrote:
>> Jeremy Manson wrote:
>
>>> If you don't have that synchronization in your code, then there you
>>> have a bug.  A data race.  Data races rot the brain and corrupt the
>>> soul.
>>
>> Yeah but my soul is already corrupt and my brain nicely folded.
>
> ... and I'm sure your clients appreciate when that comes out in your code!

Clients?

As I'm sure you are aware, most normal people find it very difficult to
interpret Chapter 17. Applying the rules directly is difficult. Roach
motel is all well and good, but if it isn't exact, how do I know the set
of possible things that could go wrong? As someone trying to ensure the
absence of bugs, I don't care what a compiler can do but what it cannot.

Tom Hawtin
--
Unemployed English Java programmer
http://jroller.com/page/tackline/

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: synchronized on construction

Jeremy Manson
Thomas Hawtin wrote:

> Jeremy Manson wrote:
>> Thomas Hawtin wrote:
>>> Jeremy Manson wrote:
>>>> If you don't have that synchronization in your code, then there you
>>>> have a bug.  A data race.  Data races rot the brain and corrupt the
>>>> soul.
>>> Yeah but my soul is already corrupt and my brain nicely folded.
>> ... and I'm sure your clients appreciate when that comes out in your code!
>
> Clients?

As in, anyone who uses code you write.  Just a little levity.


> As I'm sure you are aware, most normal people find it very difficult to
> interpret Chapter 17. Applying the rules directly is difficult. Roach
> motel is all well and good, but if it isn't exact, how do I know the set
> of possible things that could go wrong? As someone trying to ensure the
> absence of bugs, I don't care what a compiler can do but what it cannot.

I am aware of this.  Roach motel is really a rule of thumb for compiler
writers more than for working programmers.

Working programmers should try to think about these properties in terms
of happens-before, which is exact, and, although a little tricky, is
actually a pretty good abstraction once you wrap your mind around it.
In the example we were discussing, if the read happens-before the write,
the read is guaranteed not to see the write.  Therefore, the compiler
cannot move it to a place where the read might see it.

                                        Jeremy
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

JCiP still relatively inexpensive

Pete.Soper
In reply to this post by Thomas Hawtin
USD$28.34 at Amazon
This is the current deal of the year for Java programmers.

-Pete
(No direct or indirect financial connections to the authors. Just
marveling that this price can be for real!)
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: JCiP still relatively inexpensive

Brian Goetz
Its a screaming deal.  Buy ten!

Pete Soper wrote:
> USD$28.34 at Amazon
> This is the current deal of the year for Java programmers.
>
> -Pete
> (No direct or indirect financial connections to the authors. Just
> marveling that this price can be for real!)
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: JCiP still relatively inexpensive

Jeff Schultz
In reply to this post by Pete.Soper
> USD$28.34 at Amazon
> This is the current deal of the year for Java programmers.

And, it's even shipping.

> -Pete
> (No direct or indirect financial connections to the authors. Just
> marveling that this price can be for real!)

Same.


    Jeff
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest