[concurrency-interest] concurrency puzzle

Kevin Condon conivek at gmail.com
Mon Sep 11 17:06:07 EDT 2006


> Wow! That is a very subtle distinction. I'm not sure there are any practical
> consequences arising from it but I find it disconcerting to have this
> difference.

This isn't *exactly* the same thing, but I think there is a practical
consequence for a similar situation when populating non-serialized
fields in readObject().  For some Serializable class MyObject:

  private transient Object mutex;  // needs to be volatile
  private int f;

  public MyObject() {
    initTransient();
  }

  private void readObject(ObjectInputStream in) throws ... {
    initTransient();
    synchronized (mutex) {
      in.defaultReadObject();
    }
  }

  private void initTransient() {
    // bad, no synchronization on the non-volatile field init
    mutex = new Object();
  }

  private void writeObject(ObjectOutputStream out) throws ... {
    // NPE, mutex init visiblility not guaranteed in all threads
    synchronized (mutex) {
      out.defaultWriteObject();
    }
  }

  public int getF() {
    // NPE, mutex init visiblility not guaranteed in all threads
    synchronized (mutex) {
      return f;
    }
  }

  public void setF(int f) {
    // NPE, mutex init visiblility not guaranteed in all threads
    synchronized (mutex) {
      this.f = f;
    }
  }

T1:
  volatile MyObject o;
  ...
  o = (MyObject) in.readObject();

T2:
  int v = o.getF();  // might get a NPE due to race on mutex value
  // same NPE potential with o.setF() and with serializing the object ...

If I didn't have to serialize, I'd just make mutex final.  I think
making mutex volatile fixes the problem with potential NPEs, but then
you incur performance costs for both synchronization and volatile
semantics.  Is there some other option that I'm missing?  (Please
assume I don't want to do synchronize (this), because more complex
classes might not want to expose internal locks to avoid deadlock.)

This scares me because it's so easy to forget to do (I definitely
have) and because of the performance costs imposed (even if they may
be small).  In general remembering to synchronize properly during
construction and deserialization is just too easy to forget.

Regards,
Kevin


More information about the Concurrency-interest mailing list