volatile

T

Timo Nentwig

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 )
{
}
}

}
}
 
T

Timo Nentwig

Okay, it isn't requird for cumulativeTime, sure, but what about the
other fields?
 
T

Timo Nentwig

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?
 
M

Mike Schilling

Timo Nentwig said:
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.
 
T

Timo Stamm

Timo said:
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.
 
T

Timo Stamm

Timo said:
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
 
T

Timo Nentwig

Timo said:
| 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);
}
 
T

Timo Stamm

Timo said:
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
 
M

Mike Schilling

Timo Stamm said:
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.
 
T

Thomas Hawtin

Timo said:
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
 
T

Timo Nentwig

Mike said:
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);
}
 
M

Mike Schilling

Timo Nentwig said:
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.
 
T

Timo Nentwig

Mike said:
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()).
 
P

Patricia Shanahan

Timo said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top