[concurrency-interest] Annotations for declaring thread-safety properties of Java elements

kevin bourrillion kevinb at google.com
Thu Nov 1 13:56:42 EDT 2007


Thanks for the 308 reminder; I had forgotten about that.  Your
response was helpful; thanks again.


On Oct 30, 2007 12:00 PM, Tim Peierls <tim at peierls.net> wrote:
> Kevin,
>
> The JCiP annotations are deliberately few. We were tempted to try to capture
> a more complete semantics, and I vaguely recall that we even sketched out
> something along these lines based on Doug Lea's concurrency property
> "checklist", but our primary concern was to present a simple enough system
> that absolutely anyone could hope to use it, not just motivated and talented
> library designers such as yourself.
>
> But that's no excuse, and you still want to document your library. If you
> haven't already, take a look at the most recent proposal from the ministry
> for putting things on top of other things (JSR 308). I think it goes a long
> way towards answering your needs. For example, imagine that Immutable were
> declared as follows:
>
>  @Documented
>  @Target({TYPE, TYPEREF})  // currently only @Target(TYPE)
>  @Retention(RUNTIME)
> public @interface Immutable {}
>
> Then you have no need of @ReturnsThreadSafe, because you can annotate the
> return type directly:
>
>   static <E> @Immutable Set<E> immutableSet() { ... }
>
> The JSR 308 proposal also includes hints about annotations like @ReadOnly,
> though its scope does not extend to defining the semantics of these.
>
> The big problem with all of this, of course, is that you can't annotate your
> library with it, at least not officially, until Java 7 at the earliest. But
> it might help guide you in devising an interim measure that stands a chance
> of harmonizing with any later developments.
>
> --tim
>
>
>
> On 10/30/07, kevin bourrillion < kevinb at google.com> wrote:
> >
> >
> >
> > Hi folks.
> >
> > I'm interested in cultivating best practices for documenting the
> > concurrency-related behavior of types, methods, and fields in a very
> > clear and precise way.  I really like the concept behind the
> > annotations described in JCIP, but has anyone put any thought and/or
> > work into fleshing out a more complete set of annotations?
> >
> > @Immutable, @ThreadSafe and @NotThreadSafe are nice, but can only be
> > applied to types.  So they can't, for example, make any distinction
> > between a plain HashSet and a Collections.synchronizedSet() because
> > both are of type Set.
> >
> > So I find myself wishing for annotations such as @ReturnsImmutable,
> > @ReturnsThreadSafe and @ReturnsNotThreadSafe, which could be applied
> > to a method to describe the properties of whatever object that method
> > returns.  This annotation could match or strengthen whatever
> > thread-safety assertion is made by the returned type (weakening the
> > guarantee would be nonsensical and an analyzer should probably emit a
> > warning).  Would these be good to have?
> >
> > Next, consider a method which returns some result based on at least
> > one mutable parameter. Suppose the method is thread-safe, in that it
> > won't corrupt the state of any object.  It still feels necessary to
> > document in some clear way how this method behaves when any of its
> > parameters are being concurrently modified.  Is it...
> >
> > - Safe? (will produce a reasonably 'correct' answer according to its spec)
> > - Unsafe? (might throw an exception, as documented in its
> > specification, but at least won't return a bad answer)
> > - Dangerous? (might give corrupted answer; its spec uses the "results
> > are undefined" weasel words)
> > - others....?
> >
> > Is there value in being able to annotate method such as
> > ConcurrentHashMap.put() as @Atomic, and ConcurrentHashMap.putAll() as
> > @NotAtomic?  (I'm specifically asking about concurrent atomicity, but
> > there is the other issue of failure atomicity....)
> >
> > If you could annotate methods which are allowed to mutate the state of
> > the instance as @Mutates, would this help in recognizing situations
> > where it may be safe to assume thread-safety via "effective
> > immutability"?  What about a method of a mutable type which is based
> > only on immutable data -- method which will always return the same
> > value/instance no matter what?  @Fixed?
> >
> > I'll stop there.  I don't want to propose a slew of annotations just
> > for the fun of it; I really just want to find what feels like the
> > right level of precision at which I should annotate my own libraries
> > like the google collections, so that with tool support our users could
> > get some really helpful warnings.  I feel like it's quite a challenge
> > for even strong, intermediate developers to grasp the nuances of
> > "concurrency stuff", and by having clearly defined and documented
> > annotations used -- in good taste of course -- we can really help them
> > out.
> >
> > Would love to hear ideas from the list.
> >
> >
> >
> > On 10/23/07, kevin bourrillion <kevinb at google.com > wrote:
> > > Hello,
> > >
> > > I'm undertaking to rigorously document the API of the Google
> > > Collections Library (Java) to convey its concurrency-related
> > > guarantees in clear and precise terms.  I'd like to develop a set of
> > > annotations I can use for this, so that one day, our users can get
> > > informed by their static analysis tools of any suspicious code they
> > > write using our API.
> > >
> > > Background:  Java Concurrency In Practice.
> > > -----------------------------------------------------
> > >
> > > The idea came first from the book, "Java Concurrency In Practice."  In
> > > fact, the authors published their annotations in a JAR, which I
> > > checked in to third_party, before I realized that these only barely
> > > scratch the surface of what is really needed.  Let me quickly explain
> > > what these do before I move on to propose what else I think we need.
> > >
> > > The three primary JCIP annotations @Immutable, @ThreadSafe and
> > > @NotThreadSafe can be applied to any type (class, interface or enum).
> > > The meanings are:
> > >
> > >   * @Immutable: Any instance of this type is expected to be immutable.
> > > (Stateless counts as immutable, and is probably not worth
> > > distinguishing.)
> > >
> > >   * @ThreadSafe: Any instance of this type is expected to be
> > > thread-safe, but may or may not additionally be immutable.
> > >
> > >   * @NotThreadSafe: I assert nothing, but I want you to know that I at
> > > least thought about it.  (Static analysis tools should always treat
> > > @NotThreadSafe and the no-annotation case the same -- that is, aside
> > > from possibly recommending when there is no annotation that one be
> > > added!)
> > >
> > > When these annotations are applied to a *final* class, they take on a
> > > stronger meaning: they are a claim by the developer that the
> > > implementation *does* fulfill the criteria, not simply an expression
> > > that any subtype *should* fulfill them.
> > >
> > > Note that a non-instantiable class containing only static members is
> > > arguably a "type" all; I do not believe that any annotations are
> > > called for in this case.  The class should be final and have a
> > > private, do-nothing constructor.
> > >
> > > What's the use?
> > > --------------------
> > >
> > > We can already do a few things with only these annotations.  Our
> > > hypothetical static analyzer should raise a warning for any of the
> > > following scenarios:
> > >
> > >   * A class is marked @NotThreadSafe, or has no thread-safety
> > > annotation, but at least one supertype of this class is marked either
> > > @ThreadSafe or @Immutable.
> > >
> > >   * A class is marked @ThreadSafe, but at least one supertype is
> > > marked @Immutable.
> > >
> > > In short, a subtype cannot weaken the guarantee of a supertype,
> > > without producing a warning.  Adding a claim such as @Immutable to a
> > > type has a cascading effect to all subtypes; they must also add the
> > > same or stronger claim to avoid a warning.
> > >
> > > Then what?
> > > ------------------
> > >
> > > Well... that's it!  That's just about where the usefulness of the JCIP
> > > annotations runs out (there is also a @GuardedBy annotation, but this
> > > is used to document implementation, not API).
> > >
> > > I'd like to say "now the static analysis tools can warn if an instance
> > > not known to be thread-safe is published to multiple threads."
> > > However, this doesn't work; the analyzer has no way of knowing that
> > > 'new HashSet()' is unsafe while both Collections.synchronizedSet () and
> > > Collections.unmodifiableSet() are safe, because these all share the
> > > same type, Set.
> > >
> > > The same goes for a public static final field in CONSTANT_CASE; we'd
> > > like to make sure people don't do this for a mutable object, but we
> > > really can't.
> > >
> > > (I'm sure I'm missing some things that really can be done.)
> > >
> > > So now what?
> > >
> > > Method annotations
> > > ---------------------------
> > >
> > > To be used for methods with non-void, non-primitive return types:
> > >
> > >   * @ReturnsImmutable: Declares that the instance returned by any
> > > implementation of this method is expected to be immutable.
> > >
> > >   * @ReturnsThreadSafe: Declares that the instance returned by any
> > > implementation of this method is expected to be thread-safe, possibly
> > > immutable.
> > >
> > >   * @ReturnsNotThreadSafe: Declares nothing of the sort, thank you
> > > very much; don't spread it around.
> > >
> > > A method may not weaken the guarantee of a method it implements or
> > > overrides; only match it or strengthen it.  It also may strengthen any
> > > guarantee made by the *type* being returned (this is key to resolving
> > > the problem in the Set example above).  It makes no sense for it to
> > > claim to weaken the guarantee made by the type, so this should be
> > > flagged as a warning and fixed to avoid confusion.
> > >
> > > Just as the meaning of a type annotation is stronger when applied to a
> > > final class, the meaning of a method annotation becomes stronger when
> > > applied to a static method, final method, or method of a final class.
> > >
> > >   * @ThreadSafe.  Same annotation as above, but a slightly different
> > > meaning when applied to a method.  It's easiest to start by
> > > considering only what this annotation means when applied to a *static*
> > > method.  It means that the method will perform correctly regardless of
> > > any concurrent modifications happening to any of its *parameters*.
> > > Obviously, if all parameters are primitive or of @Immutable types,
> > > then the method is categorically @ThreadSafe (undecided whether the
> > > annotation should be used or elided in this case).  However, even one
> > > non- at Immutable parameter raises the question -- even if the parameter
> > > type is @ThreadSafe!  A simple example:
> > >
> > >   public static Object getLastElement(CopyOnWriteArrayList list) {
> > >     return list.get(list.size() - 1);
> > >   }
> > >
> > > COWAL is thread-safe, but the method is not.
> > >
> > > Considering how @ThreadSafe applies to instance methods is trickier,
> > > and I'll punt on it for now.
> > >
> > >   * @Atomic.  On a write operation, signifies that other threads are
> > > guaranteed not to observe the object in an intermediate state with
> > > part of the work of the method completed.  For example,
> > > ConcurrentHashMap.put(K,V) is atomic because no thread will ever
> > > observe a partially-created entry, such as one having the key set but
> > > the value still null.   ConcurrentHashMap.putAll(Map) is not atomic;
> > > another thread may observe only 42 of the entries having been added.
> > > [The term 'atomic' also carries implications for behavior in the face
> > > of an exception; you expect a failed atomic method call to leave the
> > > data in an untouched state, while a failed non-atomic call may have
> > > left the data corrupted. I'm not sure whether we want to incorporate
> > > or steer clear of that meaning for purposes of this annotation.]
> > >
> > >   * @Read, @Write. (Or to be precise, @WillNotModifyState and
> > > @MightModifyState.)  Obviously an @Immutable type may not have @Write
> > > methods, and a method may not be @Write if the method it overrides or
> > > implements is @Read.  These could potentially be used to understand
> > > when it's safe to exploit the "effective immutability" of a factually
> > > mutable instance; but I'm not sure.
> > >
> > > -------------
> > >
> > > You know, I've been typing this email all day, so let me just leave it
> > > at this for now, and see if any discussion comes of it.  dinner time!
> > >
> > > thanks for reading.
> > >
> > >
> > >
> > > --
> > > Kevin Bourrillion @ Google
> > > go/javalibraries
> > > google-collections.googlecode.com
> > > google-guice.googlecode.com
> > > jsr-310.dev.java.net
> > >
> >
> >
> > --
> > Kevin Bourrillion @ Google
> > go/javalibraries
> > google-collections.googlecode.com
> > google-guice.googlecode.com
> > jsr-310.dev.java.net
> > _______________________________________________
> > Concurrency-interest mailing list
> > Concurrency-interest at altair.cs.oswego.edu
> > http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
> >
>
>



-- 
Kevin Bourrillion @ Google
go/javalibraries
google-collections.googlecode.com
google-guice.googlecode.com
jsr-310.dev.java.net


More information about the Concurrency-interest mailing list