Bill wrote:
> The problem is that there is far too much existing code that publish 
> references to objects during the construction of that object. Any 
> class that starts a thread within the constructor will typically 
> expose the incompletely constructed object. Any class that creates 
> instances of inner classes in their constructor will store references 
> to the outer object into the heap before the outer object is 
> completely constructed (whether or not this is publishing the object 
> is a tricky question).
> 
> Given the design of Java, there is often no way to get around this 
> (other than to mandate the use of factories). Sometimes, objects do 
> need to have associated threads. Doug, who knows better, had some 
> examples of such objects in his JSR-166 slides.
Here's the one I think Bill had in mind:
  class LoggedService { // ...
    final Queue msgQ = new LinkedQueue();
    public void serve() throws InterruptedException {
      String status = doService();
      msgQ.put(status);
    }
    public LoggedService() { // start background thread
      Runnable logger = new Runnable() {
        public void run() {
          try {
            for(;;)
              System.out.println(msqQ.take());
          }
          catch(InterruptedException ie) {} }};
      new Thread(logger).start();
    }
  }
In practice, you rarely want to start a thread in a constructor, but I
illustrated in this way to make it fit on one slide. In any case,
aren't examples like this handled by requiring that parent thread make
available all variables to a new child thread? I'm newly confused
about where the problem is here.
The main contexts that demand the use of factory methods are ones
where you'd otherwise have something like:
class X {
  final static Vector instances = new Vector();
  X() {
    instances.add(this);
  }
}
class Y extends X {
  final Field aField;
  Y() {
    // implicit super() call here.
    aField = ...
  }
}
The subclass has no way of controlling exposure. So you'd need to
rework this to use public static factory methods with private
constructors etc, which can itself be error-prone. Since you can't
inherit static methods, each subclass needs to invoke the proper
initialization methods:
class X {
  final static Vector instances = new Vector();
  protected void init() { instances.add(this); }
  private X() {}
  public static X newX() {
    X x = new X();
    x.init();
    return x;
  }
}
class Y extends X {
  final Field aField;
  private Y() { aField = ...   }
  public static Y newY() {
    Y y = new Y();
    y.init();
    return y;
  }
}
And there are many cases where you can't take this approach anyway.  A
year or so ago, we discussed similar problems with the widespread use
of no-arg constructors plus init() methods in JavaBeans etc.  Because
of JavaBeans instantiation conventions (normally using
Class.newInstance()), these classes rarely use factory methods that
would hide the object between default-construction and proper
initialization.  Plus, they cannot usually use final fields because
the values only become known in init(). I still don't see any way for
people to deal with this except for synchronizing (at least parts of)
nearly all methods. This is not usually a big performance concern with
JavaBeans (they have other overhead anyway) but still a correctness
concern -- people often don't synchronize them because it is not
obvious that they need to.
-Doug
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel
This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:38 EDT