Re: JavaMemoryModel: Idiom for safe, unsynchronized reads

From: Raymie Stata (stata@pa.dec.com)
Date: Tue Jun 29 1999 - 11:12:21 EDT


>> Raymie writes:
>>
>> If we are really interested in helping unsophisticated programmers
>> write correct multi-threaded programs, then we must teach them a
>> simple religion: _all_ accesses to shared variables must be protected.
>> This is a very easy religion to learn.

> Josh writes:
> As I said previously, I think that it's not an easy religion to
> learn. Intuitively, synchronization is for insulating one thread
> from changes made by another. People just don't think that it's
> necessary for immutable objects.

I think we've gotten to the crux of our disagreement. Let me try to
argue this point.

First, Josh names a number of smart and experience people who don't
yet understand my proposed programming principle. Smart people are
always looking for clever ways around simple principles, so it's not
surprise that they don't buy into this principle. However, this
doesn't make the principle hard to learn (although it's obviously hard
to reprogram smart people who have rejected this simple principle :-)

Second, let's grant for the moment that the principle "all accesses to
shared variables" is indeed hard to learn. We still have to consider:
Is it harder to learn than the alternative? What exactly are the
alternative principles?

Doug Lea writes "immutable objects are threadsafe." However, if I were a
programmer sitting down to make coding decisions, then I wouldn't find this
to be a very instructive principle.

Josh writes:

  "...synchronization is only for mutable variables, i.e., those that
  can be modified after they're 'first published.' [Synchronization
  is not needed for variables that are not modified after they are
  first published.]"

Although this sounds simple on the surface, I think it is error-prone
and that it has more subtleties than does my principle.

By Josh's argument, the following is definitely correct:

  // Version X
  static String foo; // Immutable
  public String getFoo() {
    if (foo == null) foo = new String(..);
    return foo;
  }

Now consider the following:

  // Version Y
  static String foo[]; // Immutable
  public String[] getFoo() {
    if (foo == null) {
      foo = new String[...];
      for (int i = 0; i < ...; i++) foo[i] = new String(..);
    }
    return foo;
  }

Here, the newly allocated String array is "published" to foo before
it's initialized, so by Josh's standards this code is wrong. Now, if
programmers were steeped in the religion of "no unsynchronized access
to shared variables", then they would never think to write (Y).
However, it seems likely that programmers who think that (X) is okay
would be tempted to write (Y). This is what I mean when I say that
Josh's principle is error prone.

Now consider the following variation:

  // Version Z
  static String foo[];
  public String[] getFoo() {
    if (foo == null) {
      String[] tmp = new String[...];
      for (int i = 0; i < ...; i++) tmp[i] = new String(..);
      foo = tmp;
    }
    return foo;
  }

This code avoids publishing the new array until it's initialized, so
it satisfies Josh's principle. However, for this code to work, the
JMM would have to be Sequential Consistency (SC). No matter the
merits of Mark Hill's paper, the fact is that there will be many
architectures in the future that support models more relaxed than SC,
especially NUMA architectures. SC will impose a very large cost on
all Java implementations for the sake of very few programs that are
written like (Y).

So let's say we amend Josh's principle such that (Z) is _not_
acceptable. The amended principle will have to make (X) okay but (Z)
not okay. How do you explain this to programmers? Is this
explanation easier to learn or any more intuitive than the simple
injunction "do not access shared variables without synchronization"?

I pose the following challenge to Josh and others who would advocate
some principle other than "do not access shared variables without
synchronization." What principle(s) do you advocate? What's needed
here is _not_ a detailed JMM spec -- that comes later -- but a simple,
easy-to-learn, easy to apply principle that programmers can keep in
their head. Josh posed one such principle, but it needs to be fixed
so that (a) it's vocabulary is a little more consistent ("variables"
are not published, "objects" are) and (b) it is clear on whether or
not (Z) should be allowed. (And if you use the term "immutable object", it
would be nice to have a definition, a definition that says something about
arrays as well as objects.)

Raymie
-------------------------------
This is the JavaMemoryModel mailing list, managed by Majordomo 1.94.4.

To send a message to the list, email JavaMemoryModel@cs.umd.edu
To send a request to the list, email majordomo@cs.umd.edu and put
your request in the body of the message (use the request "help" for help).
For more information, visit http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:13 EDT