JavaMemoryModel: Can final fields change?

From: Mr. Tomcat (tomcat@mobile.mp)
Date: Fri Oct 04 2002 - 21:30:38 EDT


>From what I can gather from reading about threading and the Java memory
model, it seems the only way a field can ever really be final is if it
is always used with synchronized.

Imagine that I am creating a data storage class, and some users have
read-write permission and others are read-only, and there is a
Permission object in the DataStorage object. The Permission object is
immutable, so all its instance fields are private final. It looks like
this:

/** Permissions are immutable; all instance fields are final, and there
* are no setters. */
class Permission {

        private final boolean readOnly;

        // .... other stuff

        protected Permission(boolean readOnly, ....) {
                // do a bunch of stuff that takes a while
                this.readOnly = readOnly;
        }
}

and then my DataStorage class looks like this:

class DataStorage {

        private final Permission permission;

        // ... other stuff

        protected DataStorage(....) {
                // ....
                this.permission = new Permission(true, ...);
        }
}

A single DataStorage instance can be accessed by multiple threads. A
user creates a DataStorage instance in one thread, and before the
constructor is finished, attempts to read something. When the
constructor starts, storage is allocated for the objects and instance
fields are set to default values, which in this case means that readOnly
== false, which means that until the constructor gets to the part where
it assigns readOnly = true, the user may have a permission that he
shouldn't have. The only way to defend against this is to have all
access to the boolean readOnly be synchronized, both in the constructor
and any getters. This could be quite a performance bottleneck, and it
is silly because we know that readOnly is final and atomic, so we would
hope that access to it is efficient and non-synchronized.

Am I understanding the memory model and threading correctly? If so,
this could be a very serious and subtle hole in many multi-threaded Java
apps. If it is, what is the solution? Obviously in this case, I have
intentionally made the Permissions object unsafe in its pre-constructor
state, but in other cases, the problem could be much less obvious. I
would like to make my objects immutable and therefore threadsafe without
synchronization, but at the same time I want to be sure that they are
invisible to other threads until the constructor has finished its work.

Thanks for any comments on this.

-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



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