2

Let's say I have a class that requires configuration, dependency injection etc.

public class MyClass {
   private String someConfig;
   private SomeMutableClass anotherConfig;


   MyClass() {
     // impractical to set everything in ctor
     // otherwise I'd declare someConfig final and 
     // not worry about MT safety.
   }

   void setConfig(cfg) {
     this.someConfig = cfg;
   }
   void anotherConfig(cfg) {
     this.anotherConfig = cfg;
   }

   ...

   // below is code that uses the config set before, possibly by
   // multiple threads.

}

This is a contrived example, but what if I can't easily do all the config in the ctor? Let's say the config is done early in execution and doesn't change. Strictly speaking due to the memory model I'd have to synchronize all references to someConfig. Can this requirement be relaxed in practice?

seand
  • 5,168
  • 1
  • 24
  • 37
  • 1
    If they don't change (effectively immutable), and assuming the setter is atomic (it is in your case) then your only concern is visibility, which can be addressed by making the fields volatile for example. – assylias Mar 25 '12 at 23:29
  • 1
    To quote Clint Eastwood... "Do you feel lucky today?" – Romain Hippeau Mar 25 '12 at 23:31
  • Code's gotta know its limitations (paraphrased Eastwood) – seand Mar 25 '12 at 23:35
  • I changed my snippet to use something besides Strings. Volatile would assure visibility for the string reference (immutability) but I'm not sure about mutable classes. – seand Mar 25 '12 at 23:37
  • 2
    You added a mutable object to your example. Volatile would [be sufficient in that case too with java 1.5+](http://stackoverflow.com/questions/4614331/using-volatile-keyword-with-mutable-object). – assylias Mar 25 '12 at 23:38

3 Answers3

2

Yes, by declaring the field as volatile.

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • 'volatile' would work for strings since strings are immutable. However what if we're configuring with physically mutable objects? (ex. hashes). The volatile would guarantee the this.foo reference is stable but not the actual guts of the object passed in. – seand Mar 25 '12 at 23:32
  • Actually, `volatile` would also work for simple types, but that would be all. It wouldn't work with classes. – Kiril Mar 26 '12 at 00:16
  • 2
    @Lirik and seand - volatile _will_ work. it establishes a "happens before" relationship between 2 threads, which applies to everything the thread did. therefore, populating a HashMap and then setting it as a volatile reference is a perfectly legitimate and correct way to publish the Map to other threads(assuming you don't modify the HashMap after the fact). – jtahlborn Mar 26 '12 at 00:44
  • @jtahlborn perhaps I should elaborate: volatile will work if you're doing simple assignment of one object to another, but if you're doing a deep copy, then it wouldn't work unless you perform a thread safe deep copy. Which is somewhat similar to what you're saying with regards to the HashMap. – Kiril Mar 26 '12 at 01:53
  • 1
    @Lirik - i have no idea what you are trying to say about deep copies (and you can't assign one object to another, that doesn't make sense). ultimately, you can safely publish _any_ arbitrary java class/data structure by assigning it to a volatile reference (again, assuming you do not modify it in a thread unsafe fashion at a later point in time). – jtahlborn Mar 26 '12 at 02:44
  • @jtahlborn `MyObject objOne = objTwo;`- I don't know if my semantics are incorrect, but that's assigning one object to another. The case I'm referring to is: `MyObject objOne = new MyObject(objTwo);`- using the copy constructor (i.e. deep copy) may not be thread safe, thus marking `objOne` as volatile would not help much. – Kiril Mar 26 '12 at 03:09
  • @seand It's a good point, my answer is only meant to tackle the exact scenario outlined in the question. – biziclop Mar 26 '12 at 09:54
  • @seand - actually, there is nothing wrong with that scenario either. assuming objtwo is not modified by the copy, a new object would be created (initialized from objtwo's state) and then assigned to the volatile objOne reference, safely publishing the new object's state. – jtahlborn Mar 26 '12 at 12:24
  • @biziclop sorry my orig scenario only included immutable dependencies (Strings). I've changed it. – seand Mar 29 '12 at 02:25
1

I think biziciop's straightforward answer if perfectly fine to your question. My answer speaks more to the philosophical reason for choosing one way over the other, so take it for what it's worth.

You might be able to relax requirements that you can prove, through proper testing, never happen in actuality; that is, to model the situation you're worried about in a test. I'm a fan of not over-engineering things to match the best practice, just because it's the best practice.

Then again, if a concurrent access bug comes about due to your lack of planning, either you (or some future programmer, if this is a system that you'll hand off to others) may curse you.

I suppose the question is, why do you want to avoid the requirement? Is it (1) because, in your design, it will never actually happen? Is it (2) to make code clear, which would otherwise be much uglier/harder to read/harder to maintain. Or is it (3) because of a deeper feature of multi-threading and synchronization in general?

If it is only for reason #3 (and I don't know if that applies to you specifically, but I do see a number of programmers who fall into this category), then I'd say it's not a sufficient reason, on its own, to relax the requirement. If it's for one, or both of either #1 or #2, then you might be okay, so long as you're fully aware of the trade off you're making.

jefflunt
  • 33,527
  • 7
  • 88
  • 126
1

If this class is initialized via Spring, then this definition is sufficient. No need to synchronize access or make fields volatile.

Practically speaking, if the initialization has been performed, for example, inside a synchronization block, then all local thread data has been flushed to the main memory and will be accessible to all threads for reading.

Eugene Retunsky
  • 13,009
  • 4
  • 52
  • 55
  • Let's say the init is done with a synchronized lock. (I'm guessing Spring does this?). If another thread references the config without sync I'm not sure the memory model guarantees it'll see the result of the first thread. – seand Mar 25 '12 at 23:40
  • Memory model doesn't guarantee that, but on practice if a thread which reads the data started after the write operation, it will read consistent data. I did a lot of stuff working in highly concurrent environment and I can tell you for sure - you can rely on Spring initialization without additional locks or volatile definitions. – Eugene Retunsky Mar 26 '12 at 01:28
  • this usage pattern pops up a lot (write-once configuration / dep injection without MT protection of any sort, then usage by other threads). It seems to me that if this was unreliable then much software would fall apart. – seand Mar 29 '12 at 02:23
  • Right. Also using volatile is expensive. It's very tight and produces a lot of overhead. Write once pattern is a better approach than write-once to a volatile field and pay on each read operation. – Eugene Retunsky Mar 29 '12 at 03:02