Assignment of references atomic?

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

Assignment of references atomic?

Ryan LeCompte

Hello all,

I know that assignment of doubles are potentially unsafe since they are 64 bits, but I was wonder if assignment of object references are atomic in J2SE 1.4.2 and J2SE 5.0? For example, is it safe to do the following without synchronizing the methods:

Object getObject() {

   return object;

}

 

void setObject(Object o) {

   callAnotherMethod();

   if (someCondition == true) {

      callAnotherMethod();

      this.object = o;

   }

}

Thanks,

Ryan


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

Re: Assignment of references atomic?

Joe Bowbeer
On 10/12/05, Ryan LeCompte <[hidden email]> wrote:
>
> I know that assignment of doubles are potentially unsafe since they are 64
> bits, but I was wonder if assignment of object references are atomic in J2SE
> 1.4.2 and J2SE 5.0?
>

The JMM chapter of the JLS says writes and reads of object references
are always atomic.

"Writes to and reads of references are always atomic, regardless of
whether they are implemented as 32 or 64 bit values."

http://java.sun.com/docs/books/jls/third_edition/html/memory.html

Whether unsync'd writes and reads are "safe" is another matter..

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

Re: Assignment of references atomic?

tpeierls
In reply to this post by Ryan LeCompte
Short answer: No, this is not safe, but not for the reason you think.

Longer answer: The JVM is under no obligation to make the new value of this.object (o) visible to
other threads. While it is true that any value other threads see is guaranteed to be *some* value
that was written by some thread at some point, it will not necessarily be the most *recent* value.
The value seen by other threads might be a "stale" value; in fact, it might be the field's initial
value.

The situation with doubles is even worse: not only will threads not necessarily see the most
recent value, but the value seen might not be a value that was ever written by any thread, a
so-called "out of thin air" value.

Unless you have confined all getObject/setObject calls to a single thread, or your program can
tolerate arbitrarily stale values (which is a highly unusual property and one that should be
documented carefully if you rely on it), you need to guard all accesses to the field with some
kind of locking. The simplest way to do this is, as you implied, to add the synchronized keyword
to methods that access this field.

--tim

Ryan LeCompte wrote:

> I know that assignment of doubles are potentially unsafe since they are
> 64 bits, but I was wonder if assignment of object references are atomic
> in J2SE 1.4.2 and J2SE 5.0? For example, is it safe to do the following
> without synchronizing the methods:
>
> Object getObject() {
>    return object;
> }
>
> void setObject(Object o) {
>    callAnotherMethod();
>    if (someCondition == true) {
>       callAnotherMethod();
>       this.object = o;
>    }
> }

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

RE: Assignment of references atomic?

Ryan LeCompte
Tim,

Thank you for the lengthy response. This particular part of the code can
tolerate stale values that are returned from the getObject() method.
However, I want to be able to rely on the fact that the getObject() method
will EVENTUALLY return a recent update to the this.object (o) field. Am I
safe to make that assumption? Or is it possible for the JVM to always return
a stale value even if the value gets updated one more time? What about
declaring the variable volatile?

Ryan

-----Original Message-----
From: Tim Peierls [mailto:[hidden email]]
Sent: Wednesday, October 12, 2005 9:26 AM
To: Ryan LeCompte
Cc: [hidden email]
Subject: Re: [concurrency-interest] Assignment of references atomic?

Short answer: No, this is not safe, but not for the reason you think.

Longer answer: The JVM is under no obligation to make the new value of
this.object (o) visible to
other threads. While it is true that any value other threads see is
guaranteed to be *some* value
that was written by some thread at some point, it will not necessarily be
the most *recent* value.
The value seen by other threads might be a "stale" value; in fact, it might
be the field's initial
value.

The situation with doubles is even worse: not only will threads not
necessarily see the most
recent value, but the value seen might not be a value that was ever written
by any thread, a
so-called "out of thin air" value.

Unless you have confined all getObject/setObject calls to a single thread,
or your program can
tolerate arbitrarily stale values (which is a highly unusual property and
one that should be
documented carefully if you rely on it), you need to guard all accesses to
the field with some
kind of locking. The simplest way to do this is, as you implied, to add the
synchronized keyword
to methods that access this field.

--tim

Ryan LeCompte wrote:

> I know that assignment of doubles are potentially unsafe since they are
> 64 bits, but I was wonder if assignment of object references are atomic
> in J2SE 1.4.2 and J2SE 5.0? For example, is it safe to do the following
> without synchronizing the methods:
>
> Object getObject() {
>    return object;
> }
>
> void setObject(Object o) {
>    callAnotherMethod();
>    if (someCondition == true) {
>       callAnotherMethod();
>       this.object = o;
>    }
> }

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

Re: Assignment of references atomic?

tpeierls
Ryan LeCompte wrote:
> Thank you for the lengthy response. This particular part of the code can tolerate stale values
> that are returned from the getObject() method. However, I want to be able to rely on the fact
> that the getObject() method will EVENTUALLY return a recent update to the this.object (o)
> field. Am I safe to make that assumption? Or is it possible for the JVM to always return a
> stale value even if the value gets updated one more time?

That assumption is not safe. No matter how many times a thread updates the variable, other threads
will see arbitrarily stale values.


> What about declaring the variable volatile?

Ah! Yes, volatile *does* work, and is the most appropriate mechanism. I should have mentioned that
first, sorry.

The only reason you might *not* want to use a volatile is if there is a class invariant involving
more than one field, including the object field. I saw the use of a variable named someCondition
and assumed this was the case.

--tim

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

RE: Assignment of references atomic?

Ryan LeCompte
I'm not sure I completely understood your last reason for *not* using
volatile. Forgetting about the code sample from earlier, I basically have
two variables.. one is a primitive (boolean) and the other is a regular
Object reference. Is it safe to declare both of these as volatile? I want to
ensure that other threads see the most recent values of these two variables.

Ryan

-----Original Message-----
From: Tim Peierls [mailto:[hidden email]]
Sent: Wednesday, October 12, 2005 9:58 AM
To: Ryan LeCompte
Cc: [hidden email]
Subject: Re: [concurrency-interest] Assignment of references atomic?

Ryan LeCompte wrote:
> Thank you for the lengthy response. This particular part of the code can
tolerate stale values
> that are returned from the getObject() method. However, I want to be able
to rely on the fact
> that the getObject() method will EVENTUALLY return a recent update to the
this.object (o)
> field. Am I safe to make that assumption? Or is it possible for the JVM to
always return a
> stale value even if the value gets updated one more time?

That assumption is not safe. No matter how many times a thread updates the
variable, other threads
will see arbitrarily stale values.


> What about declaring the variable volatile?

Ah! Yes, volatile *does* work, and is the most appropriate mechanism. I
should have mentioned that
first, sorry.

The only reason you might *not* want to use a volatile is if there is a
class invariant involving
more than one field, including the object field. I saw the use of a variable
named someCondition
and assumed this was the case.

--tim

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

RE: Assignment of references atomic?

Mike Skells-3
In reply to this post by Ryan LeCompte
Hi,
 
Without doing something it is certainly unsafe unless the object is volatile, as there is nothing to force the object to be written or read from the global address space, so the object references could be assigning and rading data from the thread cache only
 
Object references are I believe atomic according the the JLS, bu the that does not make it threadsafe.
 
I think that you need to explain in a little more detail what you expect the bahavior to be
 
Mike


From: [hidden email] [mailto:[hidden email]] On Behalf Of Ryan LeCompte
Sent: 12 October 2005 13:00
To: [hidden email]
Subject: [concurrency-interest] Assignment of references atomic?

Hello all,

I know that assignment of doubles are potentially unsafe since they are 64 bits, but I was wonder if assignment of object references are atomic in J2SE 1.4.2 and J2SE 5.0? For example, is it safe to do the following without synchronizing the methods:

Object getObject() {

   return object;

}

 

void setObject(Object o) {

   callAnotherMethod();

   if (someCondition == true) {

      callAnotherMethod();

      this.object = o;

   }

}

Thanks,

Ryan


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

Re: Assignment of references atomic?

Brian Goetz
In reply to this post by Ryan LeCompte
There are two things going on here.

The assignment of the _reference_ is atomic -- other threads will either
see the old value, or the new value, but not gibberish.  But in the
general case, this program is still broken.  Just atomically assigning
the reference is not enough to ensure thread-safety -- you still have to
ensure that the state of the referred-to object is also properly
published.

It is possible for a thread calling getObject in this case to see a
partially constructed object; in other words, see an up-to-date value of
'object' but a stale/inconsistent/invalid version of the object's state,
because object was not properly published.

In short, no, you cannot do what you want to do.  You have to synchronize.

> Object getObject() {
>
>    return object;
>
> }
>
> void setObject(Object o) {
>    callAnotherMethod();
>    if (someCondition == true) {
>       callAnotherMethod();
>       this.object = o;
>    }
> }

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

Re: Assignment of references atomic?

Gregg Wonderly-2
In reply to this post by Ryan LeCompte


Ryan LeCompte wrote:

> Hello all,
>
> I know that assignment of doubles are potentially unsafe since they are 64 bits, but I was wonder if assignment of object references are atomic in J2SE 1.4.2 and J2SE 5.0? For example, is it safe to do the following without synchronizing the methods:
>
> Object getObject() {
>    return object;
> }
>
> void setObject(Object o) {
>    callAnotherMethod();
>
>    if (someCondition == true) {
>       callAnotherMethod();
>       this.object = o;
>
>    }
> }

The other replies so far are good information.  The only interesting point, I
think is that if this.object is not volatile, then there is no guarentee of
when, exactly, the effects of "this.object = o" will be visible to other
threads.  You will never see an inconsistant value, but you may not ever/always
see the "correct" value in other threads.  Either setObject should be
synchronized, or this.object should be volatile to make sure that the assignment
is "consistant" with any other sideeffects of calling setObject().

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

Re: Assignment of references atomic?

tpeierls
In reply to this post by Ryan LeCompte
I can't tell from your code sample whether it is safe. The relevant code looked something like this:

   void setObject(Object o) {
       ...
       if (someCondition) {
           ...
           this.object = o;
       }
   }

If your intent is that "object" only be given a new value when "someCondition" is true -- that's
what I meant by "class invariant" -- then it is *not* enough to make someCondition and object
volatiles, because the read of someCondition and the subsequent write to object do not happen
atomically. Volatiles provide visibility but not atomicity. In that case, you must use
synchronization when accessing the fields, and there is no point in making the fields volatile.

--tim


Ryan LeCompte wrote:

> I'm not sure I completely understood your last reason for *not* using
> volatile. Forgetting about the code sample from earlier, I basically have
> two variables.. one is a primitive (boolean) and the other is a regular
> Object reference. Is it safe to declare both of these as volatile? I want to
> ensure that other threads see the most recent values of these two variables.
>
> Ryan
>
> -----Original Message-----
> From: Tim Peierls [mailto:[hidden email]]
>
> The only reason you might *not* want to use a volatile is if there is a
> class invariant involving more than one field, including the object field.
> I saw the use of a variable named someCondition and assumed this was the case.

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

Re: Assignment of references atomic?

Joe Bowbeer
In reply to this post by tpeierls
Tim Peierls <[hidden email]> wrote:
>
> The situation with doubles is even worse: not only will threads not necessarily see
> the most recent value, but the value seen might not be a value that was ever written
> by any thread, a so-called "out of thin air" value.
>

Minor point: I think "out of thin air" is too strong a term to use for
the corruption that is permitted for (64-bit) longs and doubles.

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7

"For the purposes of the Java programming language memory model, a
single write to a non-volatile long or double value is treated as two
separate writes: one to each 32-bit half. This can result in a
situation where a thread sees the first 32 bits of a 64 bit value from
one write, and the second 32 bits from another write."

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

Re: Assignment of references atomic?

Jeremy Manson
Joe Bowbeer wrote:

> Tim Peierls <[hidden email]> wrote:
>
>>The situation with doubles is even worse: not only will threads not necessarily see
>>the most recent value, but the value seen might not be a value that was ever written
>>by any thread, a so-called "out of thin air" value.
>
> Minor point: I think "out of thin air" is too strong a term to use for
> the corruption that is permitted for (64-bit) longs and doubles.
>
> http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7
>
> "For the purposes of the Java programming language memory model, a
> single write to a non-volatile long or double value is treated as two
> separate writes: one to each 32-bit half. This can result in a
> situation where a thread sees the first 32 bits of a 64 bit value from
> one write, and the second 32 bits from another write."
>

It isn't actually out of thin air, which we reserve specifically for
causality discussions.  However, from the perspective of the programmer,
it might as well be...

                                        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: Assignment of references atomic?

Chris Purcell
In reply to this post by Brian Goetz
> It is possible for a thread calling getObject in this case to see a
> partially constructed object; in other words, see an up-to-date value
> of 'object' but a stale/inconsistent/invalid version of the object's
> state, because object was not properly published.
>
> In short, no, you cannot do what you want to do.  You have to
> synchronize.

Just to clarify here: you can synchronize by using the "volatile"
keyword, right? You do not need to use the "synchronized" keyword?

Cheers,
Chris Purcell

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

RE: Assignment of references atomic?

David Holmes
In reply to this post by Mike Skells-3
Mike Skells wrote:
> Without doing something it is certainly unsafe unless the object is
> volatile, as there is nothing to force the object to be written or read
> from the global address space, so the object references could be assigning
> and rading data from the thread cache only

This is not directed at Mike personally.

I'd like to try and dissuade people from explaining JMM issues this way. The
old JMM did indeed use a conceptual thread-cache, or working memory, and was
defined in terms of when things had to move between working memory and main
memory.

The new JMM says nothing about caches because that is only one potential
part of the problem - the bigger part being the compiler and the reorderings
that can occur in both hardware and software. The problem with talking about
caches is that people turn round and say "well the cache on my hardware
doesn't work like that, so I don't have to worry about this". And indeed on
some architectures you are essentially guaranteed that all values in cache
make their way to main memory. It is easier to make an argument that a
variable might be placed in a register by the compiler. :)

Cheers,
David Holmes

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

RE: Assignment of references atomic?

David Holmes
In reply to this post by Chris Purcell
> Chris Purcell writes:
> Just to clarify here: you can synchronize by using the "volatile"
> keyword, right? You do not need to use the "synchronized" keyword?

You can use the volatile keyword to ensure that things are visible and that
the right ordering is maintained.

For example, this is perfectly safe:

  volatile boolean dataReady = false;
  Object theObject;

  Thread-1                             Thread-2..n
  theObject = makeObject();            if (dataReady)
  dataReady = true;                        use(theObject);


Here there is a single writer and many potential readers. As long as the
readers see dataReady is true then they are guaranteed to see everything
that happened to theObject during makeObject().

But volatile in itself is not sufficient *if* there is a need for atomicity
between deciding to update the object and performing the update.

David Holmes

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

Re: Assignment of references atomic?

Jeremy Manson
The word synchronize is slightly overloaded here, and I think it could
use some more explanation for those unfamiliar with its use.

One meaning involves any mechanism that can be used to communicate
between threads: locking, volatiles, atomics, final fields, etc.  These
things all constitute synchronization actions.

If you want to communicate between threads, you need to use
synchronization actions, whether they be locking, volatiles, or anything
else.  This is what Brian was describing.

Another meaning is the language construct used for built-in locking, the
synchronized block.  A synchronized block implies two synchronization
actions: a lock action and an unlock action.

If you want to ensure mutual exclusion, you need to use locks, and may
use a synchronized block to do so.

For this example, it is definitely necessary to use some synchronization
action.  Depending on the desired semantics, it may or may not be
necessary to use locking (in the form of a synchronized block or a
JSR-166 lock).

                                        Jeremy



David Holmes wrote:

>>Chris Purcell writes:
>>Just to clarify here: you can synchronize by using the "volatile"
>>keyword, right? You do not need to use the "synchronized" keyword?
>
>
> You can use the volatile keyword to ensure that things are visible and that
> the right ordering is maintained.
>
> For example, this is perfectly safe:
>
>   volatile boolean dataReady = false;
>   Object theObject;
>
>   Thread-1                             Thread-2..n
>   theObject = makeObject();            if (dataReady)
>   dataReady = true;                        use(theObject);
>
>
> Here there is a single writer and many potential readers. As long as the
> readers see dataReady is true then they are guaranteed to see everything
> that happened to theObject during makeObject().
>
> But volatile in itself is not sufficient *if* there is a need for atomicity
> between deciding to update the object and performing the update.
>
> David Holmes
>
> _______________________________________________
> 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