Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / April 2006

Tip: Looking for answers? Try searching our database.

volatile

Thread view: 
Timo Nentwig - 31 Mar 2006 14:05 GMT
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 - 31 Mar 2006 15:03 GMT
Okay, it isn't requird for cumulativeTime, sure, but what about the
other fields?
Timo Stamm - 31 Mar 2006 15:56 GMT
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 Nentwig - 31 Mar 2006 15:11 GMT
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?
Mike Schilling - 31 Mar 2006 15:46 GMT
> 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.
Timo Stamm - 31 Mar 2006 16:09 GMT
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
[quoted text clipped - 3 lines]
| 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 Nentwig - 31 Mar 2006 17:23 GMT
> | 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
[quoted text clipped - 3 lines]
> | 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 - 31 Mar 2006 17:27 GMT
Also see http://javaspecialists.co.za/archive/newsletter.do?issue=122
Timo Stamm - 31 Mar 2006 17:36 GMT
Timo Nentwig schrieb:
>> | 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
[quoted text clipped - 24 lines]
>   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
Mike Schilling - 31 Mar 2006 19:13 GMT
> Timo Nentwig schrieb:
>>> | The volatile modifier requests the Java VM to always access the shared
[quoted text clipped - 29 lines]
> 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.
Timo Nentwig - 01 Apr 2006 18:22 GMT
> 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);
}
Mike Schilling - 01 Apr 2006 18:25 GMT
>> 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
[quoted text clipped - 7 lines]
>  System.out.println(thread1.value);
> }

Yes.  If you're sharing a value between threads, volatile or sychronization
is always required.
Timo Nentwig - 02 Apr 2006 13:42 GMT
> > So, volatile would be required in both cases?
> >
[quoted text clipped - 5 lines]
> 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()).
Patricia Shanahan - 02 Apr 2006 14:21 GMT
>>>So, volatile would be required in both cases?
>>>
[quoted text clipped - 9 lines]
> 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
Thomas Hawtin - 01 Apr 2006 08:31 GMT
> 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;
[quoted text clipped - 16 lines]
>                     {
>                         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
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.