Thread Safe

N

ndxp

class safe {

public static int foo;

public static void setfoo (int x) { foo = x; }

public static void getfoo() { return foo; }

}

I read somewhere, for java the methods setfoo and getfoo are atomic.
Does
that mean, that I don't have to declared the methods synchronized ?

-t
 
C

Chris Uppal

I read somewhere, for java the methods setfoo and getfoo are atomic.

They are atomic, yes.
Does
that mean, that I don't have to declared the methods synchronized ?

No, it does not mean that. You have to use a synchronised block (or declare
the relevant data volatile) or else changes made by one thread are not
guaranteed to be seen by any other thread. "Atomic" only means that no thread
will see /part/ of the assignment (e.g. the high 16-bits set to the new value,
but the low 16-bits still with the old value).

-- chris
 
N

ndxp

chris,

can throw more light on this ?

Atomic" only means that no thread
will see /part/ of the assignment (e.g. the high 16-bits set to the new value,
but the low 16-bits still with the old value).


thanks
 
B

Benji

class safe {
public static int foo;
public static void setfoo (int x) { foo = x; }
public static void getfoo() { return foo; }

I read somewhere, for java the methods setfoo and getfoo are atomic.
Does
that mean, that I don't have to declared the methods synchronized ?

the methods are atomic in the sense that the only operation they do
(reading and writing to a field) is guarenteed to be carried out
uninturrupted.

However, "thread safe" is tricky. What a later poster is referring to is
the fact that foo can be set by one thread on one processor, and the value
will not propagate immediately to the other processor.

however, I disagree with the other poster in that I think this is as thread
safe as you can possibly get it - because there is no case in which you
would need the value of foo to be immediately propagated across threads
in which you were not using a synchronized block, which would propagate the
values. I would be very interested if someone could come up with an
example where synchronized would help anything as far as correctness of a
program goes.

"correct values" are a tricky subject with threads, because it's all a
relative thing. usually you go for "the most correct value", with the
caveat that "I won't require any better precision". (similar to distributed
time protocols)
 
B

Benji

J. Verdrengh said:

The author does not explain the problem with the following code:
Thread1 Thread2
... MaybeSafe.setFoo(1);
MaybeSafe.setFoo(2); ...
... MaybeSafe.getFoo();

If there's no relationship between the two calls to setFoo, then you
shouldn't be able to have a guarentee about which one's value will
propagate to getFoo. The only way that this can affect the correctness of
the program is if there is some dependant relationship between setFoo(1) and
setFoo(2) - however, if there is a dependant relationship between them, it
would be non-atomic, and would require a synchronized block, which would
create a write barrier, and flush the values, and so our "problem" goes
away.

He also criticizes java's implementation of get and set properties, but
I'm not sure the problem exists there.

I feel like maybe I'm missing something important, since he seems to have
far more experience than I do - can anyone explain to me a sitaution in
which his example could actually create a problem?
 
B

Benji

can throw more light on this ?

What chris was talking about could be better explained by this: let's say
you have a 'field' that is actually two fields, and you have to set the
two fields together. So let's say this is your class:

public class Modulus
{
private int numerator;
private int denominator;
public setValue(int numerator, int denominator)
{
this.numerator = numerator;
//thread context switch could happen here
this.denominator = denominator;
}
public double getValue()
{
return ((double)numerator)/denominator;
}
}

in the example, you could call setValue, and if the thread switched out at
the specified point, the object could be left in an inconsistant state.
(the numerator would be set, but the denominator would not - in other words,
it would have a value that you never specified)

this can actually happen if you use a long or a double - assignment happens
in multiple steps that can have a thread switch happen between the steps.
 
A

Alun Harford

Benji said:
What chris was talking about could be better explained by this: let's say
you have a 'field' that is actually two fields, and you have to set the
two fields together. So let's say this is your class:

public class Modulus
{
private int numerator;
private int denominator;
public setValue(int numerator, int denominator)
{
this.numerator = numerator;
//thread context switch could happen here
this.denominator = denominator;
}
public double getValue()
{
return ((double)numerator)/denominator;
}
}

in the example, you could call setValue, and if the thread switched out at
the specified point, the object could be left in an inconsistant state.
(the numerator would be set, but the denominator would not - in other
words,
it would have a value that you never specified)

this can actually happen if you use a long or a double - assignment
happens
in multiple steps that can have a thread switch happen between the steps.

Not it can't. Get an introduction to bytecode, it's very useful stuff.

Alun Harford
 
R

Roedy Green

Not it can't. Get an introduction to bytecode, it's very useful stuff.

In an interpreted machine with green threads that would be so, but not
after the code is converted to machine code with OS threads as it is
in hotspot.. You can then get a context switch at any time. Task are
completely unaware of when they happen so they can't very well patch
things to avoid them except at byte code instruction boundaries..
Tasks have full amnesia of the time they were out unless they check
the CPU cycle clock.

Unless Java is doing something very clever, threads are left in an
inconsistent state when other threads take over.
 
N

ndxp

I'm still confused ! I don't have much experience in thread programing.
Best way, I guess would be to write a "proof of concept" program which
should indicate that this little piece of code is thread safe or not. I
would like to run this on all JVMs.
 
J

Jaakko Kangasharju

Benji said:
The author does not explain the problem with the following code:
Thread1 Thread2
... MaybeSafe.setFoo(1);
MaybeSafe.setFoo(2); ...
... MaybeSafe.getFoo();

If there's no relationship between the two calls to setFoo, then you
shouldn't be able to have a guarentee about which one's value will
propagate to getFoo.

That's exactly the problem that the author describes. Without
synchronization in Thread1 and Thread2 you are not guaranteed that the
effect of setFoo in Thread1 is ever seen by Thread2.
The only way that this can affect the correctness of the program is
if there is some dependant relationship between setFoo(1) and
setFoo(2) - however, if there is a dependant relationship between
them, it would be non-atomic, and would require a synchronized
block, which would create a write barrier, and flush the values, and
so our "problem" goes away.

You're right, it's not really a safety issue, but more of a liveness
issue (safety = nothing undesirable happens, liveness = something
desirable happens). Presumably if you call a set method you want the
new value to be seen by the whole program, so you need to synchronize
(or if you are just getting and setting a single primitive value, make
it volatile).
He also criticizes java's implementation of get and set properties, but
I'm not sure the problem exists there.

It is the same thing. You are not guaranteed that the properties set
by one thread with setProperties are ever seen by other threads
because there is no synchronization.
 
B

Benji

Alun said:
Not it can't. Get an introduction to bytecode, it's very useful stuff.

You might not want to go around telling people to get introductions to
things that you don't understand yourself, luv. :-*

Just because the bytecode operation is one step doesn't mean that it's
going to be translated into one step in the native code that is compiled
by the VM.

The Java Memory Model does not guarentee that double and long will be
written atomically. See

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7
 
B

Benji

I'm still confused ! I don't have much experience in thread programing.
Best way, I guess would be to write a "proof of concept" program which
should indicate that this little piece of code is thread safe or not. I
would like to run this on all JVMs.

Actually, that's probably not a good way of testing it. Especially since
you probably have a single processor machine, in which case you're never
going to see this behavior. Even if you have a dual processor machine
(hyperthreading does not count), a P4's memory architecture has stronger
guarentees than the java memory model, so you're still not going to see
all of the possible problems. Not only that, but actually finding a
threading bug could take days of running the same code over and over again.

You're much better off understanding what's going on.

In your case, I seriously doubt that synchronizing will help anything with
accessors and modifiers like your original question asked. However, if
you don't want to put the time into learning how threading stuff works, it
might be better just to slap synchronized around stuff when in doubt - it
wont' slow your program down that much unless it's something that's in a
really tight loop.
 
B

Benji

Jaakko said:
It is the same thing. You are not guaranteed that the properties set
by one thread with setProperties are ever seen by other threads
because there is no synchronization.

I think I agree with you as far as what you're saying happens...

however, you're also not guarenteed that the setting thread won't get
context switched out right before it sets the properties - and then the
system will go for even longer before getting the properties set. So
I think the problem that you're describing (which really isn't a problem
so much as a small delay, and is unavoidable anyway due to nondeterminism
of context switching) is different from the problem that the author is
describing, which is that the code is "not thread safe" (his words).

If he thinks that that code is not thread safe, then he can't think that
any code that doesn't use a real time scheduler is thread safe.
 
J

Jaakko Kangasharju

Benji said:
however, you're also not guarenteed that the setting thread won't get
context switched out right before it sets the properties - and then the
system will go for even longer before getting the properties set.

Of course, you cannot rely on any execution order (unless you
implement your own deterministic scheduling). But if the scheduler
does not have liveness problems (i.e., if it eventually schedules any
ready thread), then you're guaranteed that your setting runs at some
point. And when it runs, you need the synchronization to propagate
the effects to other threads.
So I think the problem that you're describing (which really isn't a
problem so much as a small delay, and is unavoidable anyway due to
nondeterminism of context switching) is different from the problem
that the author is describing, which is that the code is "not thread
safe" (his words).

I don't think it is different. To me it seems that the author is
merely misusing the term "thread safe" to cover both safety and
liveness issues. At least that's what I get from his explanation.
 
B

Benji

Jaakko said:
implement your own deterministic scheduling). But if the scheduler
does not have liveness problems (i.e., if it eventually schedules any
ready thread), then you're guaranteed that your setting runs at some
point. And when it runs, you need the synchronization to propagate
the effects to other threads.

a context switch is the same as a synchronize - the cache gets flushed and
all writes are propagated to main memory (which in turn sets the dirty bit
on the caches for other threads, and forces them to reload from main
memory the next time they access the variable).

So, I still don't think that synchronized fixes anything. (it may make it
slightly quicker, but the variable will be synchronized whenever the
thread switches for sure - which means that you aren't buying any better
guarentees for when the value will be propagated)
 
C

Chris Uppal

Benji said:
however, I disagree with the other poster in that I think this is as
thread safe as you can possibly get it - because there is no case in
which you would need the value of foo to be immediately propagated across
threads
in which you were not using a synchronized block, which would propagate
the values. I would be very interested if someone could come up with an
example where synchronized would help anything as far as correctness of a
program goes.

If by "correct" you mean that the program does what the author intended, and
what the reader would (presumably) expect, then how about this:

class Worker
implements Runnable
{
boolean m_stopRequested;

public void
run()
{
while (shouldKeepGoing())
oneStepOfWork();
}

public void
requestStop()
{
m_stopRequested = true;
}

boolean
shouldKeepGoing()
{
return m_stopRequested;
}

private void
oneStepOfWork()
{
//...
}
}

That defines a simple worker object that can be started as a separate thread,
and will continue to run until someone asks it to stop. That can malfunction.
It is pretty close to thread-safe -- the assignment to m_stopRequested, and the
reads of the same variable, are atomic, so there is no question of garbage
appearing in that variable. What's more the variable is a latch (is only ever
changed once) so there is no question of race conditions. However, without
without synchronisation in requestStop() and shouldKeepGoing(), there is no
guarantee that changes to m_stopRequested that are made in one thread will
/ever/ be visible to the thread where the worker is running. That counts as
incorrect execution in my book.

Just for completeness, this problem could also be fixed by declaring
m_stopRequested to be "volatile". That might not be a bad option in this very
particular example, but in real world code using explicit synchonisation is
usually the only simple and/or sufficient option.

-- chris
 
C

Chris Uppal

can throw more light on this ?

I'll try a different tack from that which Benji took. Maybe this will be too
low-level to help you, but it's the best I can do.

For a starter, imagine that the Java program is running on an 8-bit machine --
that's to say that the path to main memory ("bus") is 8-bits wide. (Such
machines may still exist, but you are unlikely to find yourself using one, this
is just the starting point for my example). Since the memory bus can only
carry 8 bits at a time, it will take 4 operations (at least) to write one
32-bit int to main store. So if you call:
setFoo(0x12345678);
then the underlying hardware will execute 4 separate updates of main memory.
The exact order is not important, but say it writes out:
0x12
0x34
0x56
0x78
to four consecutive 8-bit locations in main memory. That would effectively
copy the (32-bit) integer value into 32 bits of main memory. Now imagine that
a different thread on the same machine were attempting to perform:
setFoo(0xABABABAB);
If that happened at the same time as the other call to setFoo(), then -- unless
someone did something special to prevent it -- the resulting four writes of
0xAB could happen /arbitrarily/ interleaved with those of 0x12345667. So in
the end the main memory might hold:
0x 12 AB AB 78
The result is that from the point of view of the program, although we had only
ever called setFoo() with 0x12345678 and 0xABABABAB, a completely different
value could have ended up in the "foo" variable.

Things would be worse if foo was an object reference instead of a 32-bit int.
In that case, not only could we end up with a value of "foo" that had never
been supplied by setFoo(), but that value could actually be garbage. And if
that happened then the very /best/ result you could hope for is that your
program would crash immediately.

Now, this example has depended so far on the Java program running on ancient
hardware (or very constrained hardware). On more modern machines the bus is
32-bits wide, but the same sort of problem is still possible. That would
happen if the memory used to hold "foo" were not aligned on a 32-bit boundary
(very unlikely), or if the memory used to hold "x" (the parameter to setFoo())
was not held on a 32-bit boundary (possible). In such cases, the single 32-bit
value "x" cannot be transferred to main memory in a single 32-bit write. In
practise, on any /specific/ machine, there is a way to ensure that such
problems do not actually occur. And that is the point of the "atomic"
guarantee in the Java language definition. JVM implementations are /required/
to take whatever steps are necessary to ensure that such problems do not occur.

In a later post in this thread, you asked:
I'm still confused ! I don't have much experience in thread programing.
Best way, I guess would be to write a "proof of concept" program which
should indicate that this little piece of code is thread safe or not. I
would like to run this on all JVMs.

At least as far as this "atomic" issue is concerned, nobody can give you a code
snippet that shows the problem -- that's because no legal JVM is allowed to
/have/ a problem ;-)

On the other hand, as I mentioned, the "atomic" property (although very
valuable for correct programs) isn't itself enough -- not even nearly -- to be
able to write thread-safe programs. See my reply to Benji in this thread (a
few) for more details.

-- chris
 
C

Chris Uppal

I said:
without without synchronisation in
requestStop() and shouldKeepGoing(), there is no guarantee that changes
to m_stopRequested that are made in one thread will /ever/ be visible to
the thread where the worker is running. That counts as incorrect
execution in my book.

Having read you later posts in this thread, I think I should expand this a
little. The point is /not/ a liveness issue, it's not that the change might
not be propogated across within an appropriate timeframe (for the specific
application). The point is that, wthout synchronisation, there is nothing to
tell the compiler/JITer that it is not allowed to re-write a loop like:

run()
{
while (! m_stopRequested)
oneStepOfWork();
}

into:

run()
{
bolean aBool = m_stopRequested.
while (! aBool)
oneStepOfWork();
}

and that's a correctness issue. The same observation applies at hardware
level, although I don't know if there are any JVM implementation that run on
hardware (or even if there is any hardware) which defaults to such weak
propogation guarantees.

-- chris
 
J

Jaakko Kangasharju

Benji said:
a context switch is the same as a synchronize - the cache gets
flushed and all writes are propagated to main memory (which in turn
sets the dirty bit on the caches for other threads, and forces them
to reload from main memory the next time they access the variable).

Okay, this was the issue. Java's memory model does not guarantee this
(at least according to Doug Lea's book). Only synchronized and
volatile guarantee that changes made by one thread are visible to
other threads, thread context switches do not do that.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top