Synchronized methods - correct understanding?

I

Ian Pilcher

I would just like to confirm that my understanding of synchronized
methods is correct. I believe that the two code snippets below are
equivalent.

class C1
{
private int value;

public synchronized void setValue(int newValue)
{
value = newValue;
}
}

class C2
{
private int value;

public void setValue(int newValue)
{
synchronized (this)
{
value = newValue;
}
}
}

Am I correct?

Thanks!
 
M

mrandywarner

To an extent, yes. Marking a method as synchronized will ensure that
no two threads enter the method at the same time (C1). By
synchronizing on the object, you create another possible relationship
that could be good or bad depending on the desired behavior, if you
have other methods that you do not want to access during the update,
such as a getter, you can synchronize it by using the same object for
the synchronization. But I would prefer to synchronize on the actual
value that is the purpose for the synchronization. It is both simpler
to read, and limits the possibility of unnecessary, and possibly
dangerous sync relationships.

class C2 {
private Integer value;
...
public int getValue() {
synchronize(value) {
return value.intValue();
}
}
}
 
T

Thomas Fritsch

Ian said:
I would just like to confirm that my understanding of synchronized
methods is correct. I believe that the two code snippets below are
equivalent.
public synchronized void setValue(int newValue)
{
value = newValue;
}
public void setValue(int newValue)
{
synchronized (this)
{
value = newValue;
}
}
Am I correct?
Yes. Declaring a non-static method as synchronized is exactly equivalent
to wrapping the whole method body with 'synchronized(this) { ... }'.

The Language Spec elaborates more about that:
http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#30531
 
I

Ian Pilcher

Thomas said:
Yes. Declaring a non-static method as synchronized is exactly equivalent
to wrapping the whole method body with 'synchronized(this) { ... }'.

Thanks!

Not sure why I find the second version easier to understand. Too much
time spend with pthreads, I suppose.
 
A

abrasivesponge

Ian said:
I would just like to confirm that my understanding of synchronized
methods is correct. I believe that the two code snippets below are
equivalent.

class C1
{
private int value;

public synchronized void setValue(int newValue)
{
value = newValue;
}
}

class C2
{
private int value;

public void setValue(int newValue)
{
synchronized (this)
{
value = newValue;
}
}
}

Am I correct?

Thanks!

Just so you know...It would be better now to scrap the synchronized
keyword for thread management and use the new concurrency locks in Java
1.5 (if you are using that version)
The reason being you have a wider range of new mechanisms for you lock
in that package.
 
T

Thomas Hawtin

class C2 {
private Integer value;
...
public int getValue() {
synchronize(value) {
return value.intValue();
}
}
}

IIRC, Bitter Java takes that approach in one of its code examples.

There is, however, one slight problem. The technique blatantly doesn't work.

Tom Hawtin
 
T

Thomas G. Marshall

(e-mail address removed) coughed up:
To an extent, yes. Marking a method as synchronized will ensure that
no two threads enter the method at the same time (C1). By
synchronizing on the object, you create another possible relationship
that could be good or bad depending on the desired behavior, if you
have other methods that you do not want to access during the update,
such as a getter, you can synchronize it by using the same object for
the synchronization. But I would prefer to synchronize on the actual
value that is the purpose for the synchronization. It is both simpler
to read, and limits the possibility of unnecessary, and possibly
dangerous sync relationships.

class C2 {
private Integer value;

You need an actual instance here

value = new Integer(0);

...
public int getValue() {
synchronize(value) {
return value.intValue();
}
}
}

This is not a good idea in general as it goofs up compound operations later.
For example, the following:

C2 c = new C2();

c.setValue(c.getValue() + 1);

is not going to work and is going to need external synchronization one way
or the other. Using your technique, their is no way to get access to the
lock. It is far better to have the instance itself hold the lock, to allow
this:

synchronized(c)
{
c.setValue(c.getValue() + 1);
}

If you did it your way, but made the embedded Integer "value" object
exposed:

public class C2
{
// (.....code...)
public Object getLock() {return value;}
}

Then you could use it this way:

synchronized(c.getLock())
{
c.setValue(c.getValue() + 1);
}

But this is fraught with peril, because it is *not* what is expected by most
engineers.

This is to the side of whether or not you should use the

<scope> synchronized <type> <method name> {<body>}

or

<scope> <type> <method name> { synchronized(this) {<body>} }

I strongly suggest the latter unless you *absolutely* know that no
additional code will ever be added to the method that does not need
synchronization, and that you won't need the speed differential.
 
T

Thomas G. Marshall

Thomas Hawtin coughed up:
IIRC, Bitter Java takes that approach in one of its code examples.

There is, however, one slight problem. The technique blatantly doesn't
work.

Tom Hawtin

:)
 
R

Roedy Green

IIRC, Bitter Java takes that approach in one of its code examples.

There is, however, one slight problem. The technique blatantly doesn't work.

Could you please verify the failure mechanism. I gather it is that if
someone changes "value", the lock is on the old object so it does
nothing to protect. You can only lock on references you don't change.
 
T

Thomas G. Marshall

Thomas G. Marshall coughed up:

....[rip]...
If you did it your way, but made the embedded Integer "value" object
exposed:

public class C2
{
// (.....code...)
public Object getLock() {return value;}
}

Holy crap no!

It dawned on me on my way to a meeting. I've been chomping at the bit to
write this partial retraction. I forgot that the Integer classes are
immutable! This would (of course) mean he would only be creating a new one
for every value, and hence such a lock mechanism would be lost every time.

So there is yet /another/ reason to not do it that way. My other examples
stand as is.
 
T

Thomas G. Marshall

Roedy Green coughed up:
Could you please verify the failure mechanism. I gather it is that if
someone changes "value", the lock is on the old object so it does
nothing to protect.

1. That!!!

2. It doesn't allow for outside party's to have access to the lock, which
they will need for compound operations. His example is a disaster all
around.

....[rip]...
 
T

Thomas Hawtin

Thomas said:
Roedy Green coughed up:
[ said:
class C2 {
private Integer value;
...
public int getValue() {
synchronize(value) {
return value.intValue();
}
}
}

IIRC, Bitter Java takes that approach in one of its code examples.

There is, however, one slight problem. The technique blatantly doesn't
work.

Could you please verify the failure mechanism. I gather it is that if
someone changes "value", the lock is on the old object so it does
nothing to protect.

1. That!!!

Yup. synchronize locks on the object, not the variable. So after you set
the value you have now switched to a different lock. Or at least
partially switched. You would need a second lock to perform the switch
thread-safely.

Something similar does work. If you had a final reference to a map or
collection, you could update the contents with a lock on the object. As
Vector/HashTable/Collections.synchronizedXxx. As an obscure point,
technically before 1.4 you would need to distribute the object holding
the reference among threads in a thread-safe manner. From 1.5, final
makes everything alright.

In a sense, it is safe to update the reference within the synchronize
block. The reference is copied and it is always the same object locked
and unlocked. However, I can't think of a use for it off the top of my
head (although I seem to remember a situation where I could have done it).
2. It doesn't allow for outside party's to have access to the lock, which
they will need for compound operations. His example is a disaster all
around.

I have never managed to come to a decision on this. It does expose
significant implementation. For instance, it doesn't work so well with
decorators.

Writers have separate locks. This appears to have caused confusion to an
author of java.sql.DriverManager where a print and a flush are
synchronised together. Not that it particularly matters whether this
particular sequence is atomic or not.

Tom Hawtin
 
R

Roedy Green

As an obscure point,
technically before 1.4 you would need to distribute the object holding
the reference among threads in a thread-safe manner. From 1.5, final
makes everything alright.

Where did you learn about this? could you explain in code what you
mean by "distributing the object"?
 
T

Thomas Hawtin

Roedy said:
Where did you learn about this? could you explain in code what you
mean by "distributing the object"?

Initially from the Java Memory Model list. Final field semantics are
specified in section 17.5 of JLS3, although I can't give you a reference
to a good tutorial on the subject.

By "distributing the object" [reference] I mean how a reference to an
object is copied from one thread to another. For instance, you might
write the reference in a static field, then have another thread poll it.
Without synchronisation, the reading thread may see a partially
initialised object[1]. From 1.5 final instance fields are freezed at the
end of the constructor, allowing thread-safety by immutability.

In practice witting a thread-safe-by-immutability object is just doing
the obvious. Actually exploiting those properties is more difficult. As
was compromising security by the original flawed memory model. Witting
classes with correct finalisation is just silly difficult.

Tom Hawtin

[1] Assuming the static field is non-volatile and written from outside
of class initialisation and the constructor,
 
T

Thomas G. Marshall

Thomas Hawtin coughed up:
Roedy said:
Where did you learn about this? could you explain in code what you
mean by "distributing the object"?

Initially from the Java Memory Model list. Final field semantics are
specified in section 17.5 of JLS3, although I can't give you a
reference to a good tutorial on the subject.

By "distributing the object" [reference] I mean how a reference to an
object is copied from one thread to another. For instance, you might
write the reference in a static field, then have another thread poll
it. Without synchronisation, the reading thread may see a partially
initialised object[1]. From 1.5 final instance fields are freezed at
the end of the constructor, allowing thread-safety by immutability.

It would have been interesting to have the writing and reading of even /non/
static variables be synchronized in nature. It would limit your ability to
code unsafely, which is sometimes needed. However even in the 1.5 final
field case, I would still strongly suggest this not be relied upon, even in
reading only. Use synchronized accessors/mutators. The reason for this is
that there might be a point in the future where an engineer might be
convinced that the variable need not be final (for some reason), and there
goes your read protection. The problem with threading corruption is that
often your code will run for 6 hours straight and /then/ die. It's just
always worth having the *explicit* protection.


In practice witting a thread-safe-by-immutability object is just doing
the obvious. Actually exploiting those properties is more difficult.
As was compromising security by the original flawed memory model.
Witting classes with correct finalisation is just silly difficult.

Tom Hawtin

[1] Assuming the static field is non-volatile and written from outside
of class initialisation and the constructor,
 
T

Thomas G. Marshall

Thomas Hawtin coughed up:
Thomas G. Marshall wrote:

I have never managed to come to a decision on this. It does expose
significant implementation. For instance, it doesn't work so well with
decorators.

The exposing of implementation to me seems more an extension of the
interface in a way. It is, for example, far more innocuous than allowing
direct access to a member variable, to pick one thing out of a hat.

One way or another, if an object is to be thread safe and allow compound
operations, /something/ has to be done. If you want it to fold protection
entirely within the object *and* allow arbitrary compound operations, it
*is* possible to implement something that I am not 100% comfortable with:

public void runSafely(Runnable runnable)
{
synchronized (internalLock) { runnable.run(); }
}

or something similar to keep the internalLock nonpublished. Otherwise you
need to have the lock externally settable/releasable.

Synchronized arraylists, for example, require you to use themselves as the
lock, if you're going to protect against all access to it from anywhere not
under your control. At first I cringed at the idea, but have since grown
entirely comfortable with it.
 

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,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top