[concurrency-interest] Double Checked Locking in OpenJDK

Boehm, Hans hans.boehm at hp.com
Tue Aug 14 13:29:38 EDT 2012


In the setting that you describe, there is no ordering enforced between "modify ArrayList" and "read ArrayList".  Hence (modulo one or two obscure corner cases that aren't quite handled correctly), there is an alternate schedule in which they occur concurrently.  Hence there can be a high level data race on the ArrayList, and this is a client bug.  Don't do that.  It is perfectly safe to use if you follow the rules and avoid the data race.

I'm not sure I characterized 3 very well in a Java context, since Java built-in types sort-of have stronger properties.  A better characterization is probably "safely usable in code that doesn't have high level data races on the class".

Hans

From: Yuval Shavit [mailto:yshavit at akiban.com]
Sent: Tuesday, August 14, 2012 7:03 AM
To: Boehm, Hans
Cc: Joe Bowbeer; concurrency-interest
Subject: Re: [concurrency-interest] Double Checked Locking in OpenJDK

Except that, as I understand it, #3 doesn't exist. The non-threadsafe collections aren't threadsafe even if the only concurrent actions are read methods, because of memory visibility. Specifically, if you have:

   - publish ArrayList to threads A and B
   - modify ArrayList (when A and B happen to not be reading it, but without locking to ensure that)
   - A and B read ArrayList

... then that is *not* safe, because A and B are allowed to see only some of the action performed by step 2. For instance, maybe they see the list's size incremented, but don't see changes to its array. Or maybe they see everything in the ArrayList correctly, but don't see correct state in an object they read from it.

(I'm assuming that you meant by option #3 that there aren't concurrent writes, but that you don't enforce this via a lock. If you enforce it via a lock, you've externally synchronized the object and everything's fine... but in that case, the object's threadsafety-ness doesn't matter.)
On Mon, Aug 13, 2012 at 7:58 PM, Boehm, Hans <hans.boehm at hp.com<mailto:hans.boehm at hp.com>> wrote:

I tend to think in terms of several useful levels of thread-safety:



1. Immutable, as defined below.  Untrusted code can create one, and it will always look the same to every observer.  There is no danger of a security check seeing one value and a later action seeing another.  Needed for String and the like.



2. "Thread-safe".  If I'm handed one by untrusted code, I shouldn't believe it.  But method calls are linearizable, and the right happens-before relationships are introduced.  I can assume such an object is not communicated via a race, since I don't care how it behaves with untrusted code.  A lot of j.u.c. classes fit here, I think, as does Vector.



3. "Behaves like built-ins".  Concurrent calls to "read" methods or to different objects behave correctly.  Concurrent calls on the same object, when at least one logically modifies the object is a bug.  Normal default behavior for ordinary collections, e.g. ArrayList, though many of them may have some additional, more specific, guarantees.  The client protects these with locks, as would an int.



4. Really, seriously thread-unsafe.  Accesses static fields behind the scenes without locking, modifies the data structure for logically read-only operations (think splay trees), etc.



I think all of those are useful.  (In particular, 3 is incredibly useful, and really needs a better name.)  I'm not sure how many more are.



Hans




From: concurrency-interest-bounces at cs.oswego.edu<mailto:concurrency-interest-bounces at cs.oswego.edu> [mailto:concurrency-interest-bounces at cs.oswego.edu<mailto:concurrency-interest-bounces at cs.oswego.edu>] On Behalf Of Joe Bowbeer
Sent: Monday, August 13, 2012 3:02 PM
To: concurrency-interest

Subject: Re: [concurrency-interest] Double Checked Locking in OpenJDK

For completeness, here is the documentation for the @Immutable annotation from JCiP, which is more heavily laden than the standard definition, and leaves nothing to the imagination of paranoid programmers:

http://jcip.net/annotations/doc/net/jcip/annotations/Immutable.html

The class to which this annotation is applied is immutable. This means that its state cannot be seen to change by callers, which implies that

  *   all public fields are final,

  *   all public final reference fields refer to other immutable objects, and

  *   constructors and methods do not publish references to any internal state which is potentially mutable by the implementation.

Immutable objects may still have internal mutable state for purposes of performance optimization; some state variables may be lazily computed, so long as they are computed from immutable state and that callers cannot tell the difference.
Immutable objects are inherently thread-safe; they may be passed between threads or published without synchronization.


--Joe

On Mon, Aug 13, 2012 at 2:46 PM, Wolfgang Baltes wrote:
Immutability and thread safety should be considered essentially orthogonal concepts. However, the final keyword can be useful in both.

Immutability just means that the object cannot be changed after instantiation. There are several ways to achieve this, the most obvious ones are a) to make a data fields final, and b) not to provide a method that changes the values of data fields.

Thread safe publishing means that, when an object reference is shared between threads, all threads see the object only in the same state as the thread which has last modified (or instantiated) the object. There are different ways to accomplish this, the most obvious ones being to declare a fields final or volatile. Final provides the guarantee that a field can safely be published to other threads after the constructor that assigns the value is finished. If there are multiple fields, than only those that are marked final are covered by the guarantee. This is different from volatile, where instructions - such as writes to non volatile fields - that appear in the code before a write to a volatile field, are guaranteed to be executed before the first subsequent read of that volatile field, no matter in which thread this read instruction occurs. In the latter case, a non volatile field which is never modified by any method may also appear as immutable and be published in a thread safe manner.

Hence, marking a field final makes it immutable and publishable in a thread safe manner, if the reference to the object that holds the field is published after the constructor is finished.

Wolfgang.



On 2012-08-13 13:20, Ruslan Cheremin wrote:
Yes, and it is my point -- it's confusing to say "immutable" (which
form of?), confusing to say "thread safe" (in which multithreaded use
case it is safe?) and even more confusing to say both "immutable and
thread-safe" -- because actually there is (==I know) only two ways to
reach thread-safe immutability in java: "all fields final", or "all
methods sync-ed, including constructors" -- and the second one is very
rare.

For me "immutable and thread safe" seems to be equivalent to
"thread-safe immutable", which, in turn, implies safety for data race
publication. How can I claim object as "thread safe immutable", if I
can see in several states in multithreaded env.?


2012/8/13 Yuval Shavit:
This class is immutable but not thread-safe absent safe publication:

public class MyImmutable {
     private long val; // not marked final or volatile
     public MyImmutable(long val) {
         this.val = val;
     }

     public int getValue() {
         return val;
     }
}

In the absence of safe publication, a thread is allowed to see:

     - val's default value (0)
     - the value passed to the constructor
     - a word tear in which val contains only the high or low word from the
value passed to the constructor


On Mon, Aug 13, 2012 at 3:39 PM, Ruslan Cheremin wrote:
For me it is confusing: java has only one way to have really immutable
object, and this way also gives you a total thread safety even for
data race based publication. But then docs refer object as "immutable
and thread-safe" -- we still can't assume it to be really thread-safe?

It's a pity, especially because true immutability gives us some
chances of performance optimization. As in this case -- we do not
really need .path to be volatile here, if we would assume Path to be
truly immutable. volatility here required only for ensuring safe
publishing.

2012/8/13 David Holmes:
Ruslan Cheremin writes:>
But is there a way to define "safe for data race publishing"? I as
far, as I remember, "immutable and thread-safe" is standard mantra in
JDK javadocs for totally safe objects. j.l.String has same mantra --
and it is safe for any way of publishing. Does you mean, I should
explicitly add "safe even for publishing via data race" in docs? But I
can't remember any such phrase in JDK docs.
I don't recall anything in the JDK docs that mention being "totally
safe"
regardless of publication mechanism. Some classes, eg String, have been
defined such that they do have that property (for security reasons). In
general neither "thread-safe" nor "immutable" imply
safe-for-unsynchronized-publication.

Java Concurrency In Practice (jcip.net<http://jcip.net>) does define additional potential
annotations, where @Immutable would indeed capture the requirement of
safe-for-unsynchronized-publication.

David


_______________________________________________
Concurrency-interest mailing list
Concurrency-interest at cs.oswego.edu<mailto:Concurrency-interest at cs.oswego.edu>
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20120814/831a68f2/attachment-0001.html>


More information about the Concurrency-interest mailing list