volatile

Discussion in 'Java' started by Timo Nentwig, Mar 31, 2006.

  1. Timo Nentwig

    Timo Nentwig Guest

    Hi!

    I'm still not completely certain about the volatile keyword. Is it
    actually required in the example below or would it only be required if
    go() would access the fields of Stats directly (if they were
    accessible, of course)?

    Thanks
    Timo

    import java.util.Timer;
    import java.util.TimerTask;

    public class Test
    {
    class Stats
    {
    private volatile int counter = 0;
    private volatile long cumulativeTime;
    private volatile int min, avg, max;

    public Stats( final int period )
    {
    reset();

    final Timer timer = new Timer( true );

    timer.schedule( new TimerTask()
    {
    public void run()
    {
    System.out.println( "i=" + counter + ", cumulative=" +
    cumulativeTime );

    synchronized( this )
    {
    avg = counter == 0 ? 0 : (int)(cumulativeTime / counter);
    }

    reset();
    }
    }, period, period );
    }

    private void reset()
    {
    synchronized( this )
    {
    counter = 0;
    cumulativeTime = 0;
    min = Integer.MAX_VALUE;
    max = Integer.MIN_VALUE;
    }
    }

    public void register( int t )
    {
    synchronized( this )
    {
    counter++;
    cumulativeTime += t;

    if( t < min ) min = t;
    if( t > max ) max = t;
    }
    }

    public int average()
    {
    return avg;
    }

    public int min()
    {
    return min;
    }

    public int max()
    {
    return max;
    }
    }

    private static final int PERIOD = 2500;
    private static final int INTERVAL = 1000;

    public static void main( String[] args )
    {
    new Test().go();
    }

    private void go()
    {
    final Stats stats = new Stats( PERIOD );

    final Timer reporter = new Timer();
    reporter.schedule( new TimerTask()
    {
    public void run()
    {
    System.out.println( "avg=" + stats.average() + ", min=" +
    stats.min() + ", max=" + stats.max() );
    }
    }, INTERVAL, INTERVAL );

    while( true )
    {
    stats.register( (int)Math.round( Math.random() * 10000 ) );

    try
    {
    Thread.sleep( (int)Math.round( Math.random() * 5 ) + 5 );
    }
    catch( InterruptedException e )
    {
    }
    }

    }
    }
     
    Timo Nentwig, Mar 31, 2006
    #1
    1. Advertising

  2. Timo Nentwig

    Timo Nentwig Guest

    Okay, it isn't requird for cumulativeTime, sure, but what about the
    other fields?
     
    Timo Nentwig, Mar 31, 2006
    #2
    1. Advertising

  3. Timo Nentwig

    Timo Nentwig Guest

    Oops, and the synchronized isn't quite correct, introduce a mutex in
    Stats and replace any occurence of synchronized( this ) by mutex :)

    Well, anyway, what about volatile?
     
    Timo Nentwig, Mar 31, 2006
    #3
  4. "Timo Nentwig" <> wrote in message
    news:...
    > Hi!
    >
    > I'm still not completely certain about the volatile keyword. Is it
    > actually required in the example below or would it only be required if
    > go() would access the fields of Stats directly (if they were
    > accessible, of course)?


    Can you create a smaller example? My eyes glazed over trying to look at
    that much (unformatted) code.
     
    Mike Schilling, Mar 31, 2006
    #4
  5. Timo Nentwig

    Timo Stamm Guest

    Timo Nentwig schrieb:
    > Okay, it isn't requird for cumulativeTime, sure, but what about the
    > other fields?



    If you remove the code that is unrelated to the question, it is much
    easier to understand and comment on it.
     
    Timo Stamm, Mar 31, 2006
    #5
  6. Timo Nentwig

    Timo Stamm Guest

    Timo Nentwig schrieb:
    > I'm still not completely certain about the volatile keyword.



    From cephas.net:

    | The volatile modifier requests the Java VM to always access the shared
    | copy of the variable so the its most current value is always read. If
    | two or more threads access a member variable, AND one or more threads
    | might change that variable's value, AND ALL of the threads do not use
    | synchronization (methods or blocks) to read and/or write the value,
    | then that member variable must be declared volatile to ensure all
    | threads see the changed value.


    The entire JSE 5 source (3,772,776 lines) uses the "volatile" modifier
    111 times. According to my highly scientific analysis, you should not
    use the "volatile" keyword unless your code base is larger than 34,000
    lines :)


    Timo Stamm
     
    Timo Stamm, Mar 31, 2006
    #6
  7. Timo Nentwig

    Timo Nentwig Guest

    Timo Stamm wrote:
    > | The volatile modifier requests the Java VM to always access the shared
    > | copy of the variable so the its most current value is always read. If
    > | two or more threads access a member variable, AND one or more threads
    > | might change that variable's value, AND ALL of the threads do not use
    > | synchronization (methods or blocks) to read and/or write the value,
    > | then that member variable must be declared volatile to ensure all
    > | threads see the changed value.


    Yes...

    Okay, some shorter pseudo-code:

    thread1{
    int value;

    void modify(){ value++; }
    void print() {System.out.println( value ); }
    }

    thread2{
    thread1.modify();

    // IMHO I don't need volatile here:
    thread1.print();

    // but I wouldneed it here:
    System.out.println(thread1.value);
    }
     
    Timo Nentwig, Mar 31, 2006
    #7
  8. Timo Nentwig

    Timo Nentwig Guest

    Timo Nentwig, Mar 31, 2006
    #8
  9. Timo Nentwig

    Timo Stamm Guest

    Timo Nentwig schrieb:
    > Timo Stamm wrote:
    >> | The volatile modifier requests the Java VM to always access the shared
    >> | copy of the variable so the its most current value is always read. If
    >> | two or more threads access a member variable, AND one or more threads
    >> | might change that variable's value, AND ALL of the threads do not use
    >> | synchronization (methods or blocks) to read and/or write the value,
    >> | then that member variable must be declared volatile to ensure all
    >> | threads see the changed value.

    >
    > Yes...
    >
    > Okay, some shorter pseudo-code:
    >
    > thread1{
    > int value;
    >
    > void modify(){ value++; }
    > void print() {System.out.println( value ); }
    > }
    >
    > thread2{
    > thread1.modify();
    >
    > // IMHO I don't need volatile here:
    > thread1.print();
    >
    > // but I wouldneed it here:
    > System.out.println(thread1.value);
    > }


    I don't think you need "volatile" in this case. There are no
    /concurrent/ modifications: thread2 does the modification (through
    thread1.modify), and reads the value /afterwards/.


    As far as I understand it, this would be a more appropriate example:

    thread1 {
    int value;
    while (true) {
    value++;
    }
    }

    thread1 {
    while (true) {
    System.out.println(thread1.value);
    }
    }


    value should be marked volatile because the JVM could keep a copy in a
    register and thread2 would never know the modified value.


    Timo Stamm
     
    Timo Stamm, Mar 31, 2006
    #9
  10. "Timo Stamm" <> wrote in message
    news:442d5ab4$0$7760$-online.net...
    > Timo Nentwig schrieb:
    >> Timo Stamm wrote:
    >>> | The volatile modifier requests the Java VM to always access the shared
    >>> | copy of the variable so the its most current value is always read. If
    >>> | two or more threads access a member variable, AND one or more threads
    >>> | might change that variable's value, AND ALL of the threads do not use
    >>> | synchronization (methods or blocks) to read and/or write the value,
    >>> | then that member variable must be declared volatile to ensure all
    >>> | threads see the changed value.

    >>
    >> Yes...
    >>
    >> Okay, some shorter pseudo-code:
    >>
    >> thread1{
    >> int value;
    >>
    >> void modify(){ value++; }
    >> void print() {System.out.println( value ); }
    >> }
    >>
    >> thread2{
    >> thread1.modify();
    >>
    >> // IMHO I don't need volatile here:
    >> thread1.print();
    >>
    >> // but I wouldneed it here:
    >> System.out.println(thread1.value);
    >> }

    >
    > I don't think you need "volatile" in this case. There are no /concurrent/
    > modifications: thread2 does the modification (through thread1.modify), and
    > reads the value /afterwards/.
    >


    Without either volatile or synchronization, there's no guarantee thread 1
    will see a change made in thread 2; thread 1 might hold onto its previously
    cached value indefinitely.

    By the way

    value++

    should be a red flag. If two threads can both execute it, volatile isn't
    good enough, becsue you have no guarantee about how

    fetch value
    increment
    store the result in value

    get interleaved. Nothing less than

    synchronize(lock)
    {
    value++;
    }

    is reliable.
     
    Mike Schilling, Mar 31, 2006
    #10
  11. Timo Nentwig wrote:
    > I'm still not completely certain about the volatile keyword. Is it
    > actually required in the example below or would it only be required if
    > go() would access the fields of Stats directly (if they were
    > accessible, of course)?


    > private volatile int counter = 0;
    > private volatile long cumulativeTime;
    > private volatile int min, avg, max;
    >
    > public Stats( final int period )
    > {
    > reset();
    >
    > final Timer timer = new Timer( true );
    >
    > timer.schedule( new TimerTask()
    > {
    > public void run()
    > {
    > System.out.println( "i=" + counter + ", cumulative=" +
    > cumulativeTime );
    >
    > synchronized( this )
    > {
    > avg = counter == 0 ? 0 : (int)(cumulativeTime / counter);


    'this' in that position will give you a reference to your anonymous
    subclass of TimerTask. Probably not what you want.

    If you properly synchronise access to variables, then you wont need mark
    them volatile. Multiple volatile variables outside of proper
    synchronisation may not have consistent values, even if you put all the
    code on one line.

    Tom Hawtin
    --
    Unemployed English Java programmer
    http://jroller.com/page/tackline/
     
    Thomas Hawtin, Apr 1, 2006
    #11
  12. Timo Nentwig

    Timo Nentwig Guest

    Mike Schilling wrote:
    > Without either volatile or synchronization, there's no guarantee thread 1
    > will see a change made in thread 2; thread 1 might hold onto its previously
    > cached value indefinitely.


    So, volatile would be required in both cases?

    thread2{
    thread1.print();
    System.out.println(thread1.value);
    }
     
    Timo Nentwig, Apr 1, 2006
    #12
  13. "Timo Nentwig" <> wrote in message
    news:...
    >
    > Mike Schilling wrote:
    >> Without either volatile or synchronization, there's no guarantee thread 1
    >> will see a change made in thread 2; thread 1 might hold onto its
    >> previously
    >> cached value indefinitely.

    >
    > So, volatile would be required in both cases?
    >
    > thread2{
    > thread1.print();
    > System.out.println(thread1.value);
    > }


    Yes. If you're sharing a value between threads, volatile or sychronization
    is always required.
     
    Mike Schilling, Apr 1, 2006
    #13
  14. Timo Nentwig

    Timo Nentwig Guest

    Mike Schilling wrote:
    > "Timo Nentwig" <> wrote in message
    > news:...
    > > So, volatile would be required in both cases?
    > >
    > > thread2{
    > > thread1.print();
    > > System.out.println(thread1.value);
    > > }

    >
    > Yes. If you're sharing a value between threads, volatile or sychronization
    > is always required.


    But in case of thread1.print() thread2 doesn't access the value at all,
    does it? I just call a method and the value is actually accessed by
    thread1 (from method print()).
     
    Timo Nentwig, Apr 2, 2006
    #14
  15. Timo Nentwig wrote:
    > Mike Schilling wrote:
    >
    >>"Timo Nentwig" <> wrote in message
    >>news:...
    >>
    >>>So, volatile would be required in both cases?
    >>>
    >>>thread2{
    >>> thread1.print();
    >>> System.out.println(thread1.value);
    >>>}

    >>
    >>Yes. If you're sharing a value between threads, volatile or sychronization
    >>is always required.

    >
    >
    > But in case of thread1.print() thread2 doesn't access the value at all,
    > does it? I just call a method and the value is actually accessed by
    > thread1 (from method print()).
    >


    It is important to separate two concepts that I think you may be combining:

    1. Which object is accessing the data.

    2. Which thread is it doing it in.

    I suggest NOT naming classes or objects after threads. It makes your
    code unnecessarily confusing, and difficult to discuss.

    The fact that a class is called thread1 does not mean everything it does
    is run in any particular thread. If something running in thread A calls
    one of its methods, that method runs in thread A.

    The important issue for determining whether synchronization is needed is
    whether the data is modifiable and is accessed by more than one thread.

    I always try to ensure than any related group of asynchronous access
    data is under the control of a single object. The code for that object
    is responsible for keeping the data consistent, almost always by
    synchronization. That object's methods are called by everything that
    needs any access to the information the block of data represents. It is,
    of course, a good general plan for any block of tightly related data,
    but particularly so with multi-threaded access.

    Patricia
     
    Patricia Shanahan, Apr 2, 2006
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Knute Johnson

    Re: Volatile?

    Knute Johnson, Jul 1, 2003, in forum: Java
    Replies:
    17
    Views:
    1,477
    Knute Johnson
    Jul 3, 2003
  2. Doug Pardee

    Re: Volatile?

    Doug Pardee, Jul 1, 2003, in forum: Java
    Replies:
    0
    Views:
    919
    Doug Pardee
    Jul 1, 2003
  3. Replies:
    1
    Views:
    960
    Knute Johnson
    Aug 29, 2003
  4. Daniel

    Can volatile be trusted?

    Daniel, Sep 11, 2003, in forum: Java
    Replies:
    7
    Views:
    484
    Chris Uppal
    Sep 12, 2003
  5. ben
    Replies:
    5
    Views:
    623
    Ulrich Eckhardt
    Jan 11, 2005
Loading...

Share This Page