4
public class Stuff {
  private final Timer timer = new Timer(true);
  public static final int DEFAULT_TIMEOUT = 1500;
  private volatile int timeout = DEFAULT_TIMEOUT;


  public void doStuff(OtherStuff) {
     ...
     timer.schedule(timeout, ...);
  }

  public void setTimeout(int timeout) {
     this.timeout = timeout;
  }

  public int getTimeout() {
    return timeout;
  }

}

Instances of this class is accessed from just 1 thread, except the timeout variable which can be altered from another class. In my case a JMX bean, which means one can alter the timeout during runtime from a management interface.

The doStuff() could be running 100's of times/second, while the setTimeout() could be run once a week - so the ordering between someone doing setTimeout() and someone doing doWork() is not important.

Is making timeout volatile sufficient for such a case ? Will the memory model guarantee that setting this from one thread to be visible to the doStuff() method ?

Another alternative that seems safe would simply be:

public class Stuff {
  private final Timer timer = new Timer(true);
  public static final int DEFAULT_TIMEOUT = 1500;
  private int timeout = DEFAULT_TIMEOUT;
  public void doStuff(OtherStuff) {
     ...
     timer.schedule(getTimeout(), ...);
  }

  public void synchronized setTimeout(int timeout) {
     this.timeout = timeout;
  }
   public int synchronized getTimeout() {
    return timeout;
  }
}

Which of these 2 approaches would be preferred ?

assylias
  • 321,522
  • 82
  • 660
  • 783

2 Answers2

7

From a visibility perspective, both approaches are equivalent. Any read on a volatile that happens subsequently to a write on that same volatile variable is guaranteed to see the write.

So if one thread writes timeout = newValue;, any other threads subsequently calling timer.schedule(timeout) is guaranteed to see newValue.

This guarantee is specified in the JLS 17.4.5:

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

I would simply use volatile as the guarantees it provides are sufficient and it clearly shows your intent.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • There is actually no guarantee :) – Marko Topolnik Nov 27 '12 at 21:01
  • @MarkoTopolnik I was hoping you wouldn't come across this! Now we have a confused OP! – assylias Nov 27 '12 at 21:12
  • I couldn't help myself :) But basically, it is both correct and helpful to use "strong promise" instead of "guarantee". It may be more confusing to read that "subsequent" with the regular wall-clock time meaning because some things fail to make sense that way. – Marko Topolnik Nov 27 '12 at 21:15
  • What I took home from the discussion was that no jvm would breach that promise as it would break too many programs. And I haven't found a way to summarise it without making it confusing... so I stick to the bottom (if simplified) line! – assylias Nov 27 '12 at 21:23
  • For curious users, [this is what Marko refers to](http://stackoverflow.com/questions/11761552/guarantees-given-by-the-java-memory-model). – assylias Nov 27 '12 at 21:27
  • It's just that it is somewhat icky to interpret the JLS as if it does provide a guarantee. The guarantee given is that what the thread wrote before the write to the volatile is guaranteed to be visible to the reading thread---and that's the really important guarantee. Add to that the promise of timeliness---and you have it all correct and clearly explained. – Marko Topolnik Nov 27 '12 at 21:27
  • Put it another way what would you recommend for the OP's specific use case? – assylias Nov 27 '12 at 21:36
  • 1
    Clearly, the advice in your answer is absolutely correct (I've upvoted it already). The issue is only with the argumentation which supports a correct conclusion by a not-quite-correct premise. – Marko Topolnik Nov 27 '12 at 21:39
1

Despite both the approaches of the example are equivalent I think (because of the generality of the question) it's worth to talk about this:

The visibility effects of volatile variables extend beyond the value of the volatile variable itself. If the question was "will volatile also guarantee visibility of the same volatile variable?". The answer is yes.

But there is no guarantee visibility of the (if there are) other variables that are used before the writing on this variable.

From Full volatile Visibility Guarantee.

Example:

When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of ALL variables that were visible to A prior to writing to the volatile variable become visible to B AFTER reading the volatile variable.

Davide Patti
  • 3,391
  • 2
  • 18
  • 20