Java Forum / General / November 2005
Synchronized methods - correct understanding?
Ian Pilcher - 14 Nov 2005 16:59 GMT 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!
 Signature ======================================================================== Ian Pilcher i.pilcher@comcast.net ========================================================================
mrandywarner@gmail.com - 14 Nov 2005 17:10 GMT 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(); } } }
Thomas Hawtin - 14 Nov 2005 18:19 GMT > class C2 { > private Integer value; [quoted text clipped - 5 lines] > } > } 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
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Thomas G. Marshall - 14 Nov 2005 18:33 GMT Thomas Hawtin coughed up:
>> class C2 { >> private Integer value; [quoted text clipped - 12 lines] > > Tom Hawtin
:)
 Signature "So I just, uh... I just cut them up like regular chickens?" "Sure, just cut them up like regular chickens."
Roedy Green - 14 Nov 2005 20:10 GMT On Mon, 14 Nov 2005 18:19:17 +0000, Thomas Hawtin <usenet@tackline.plus.com> wrote, quoted or indirectly quoted someone who said :
>> class C2 { >> private Integer value; [quoted text clipped - 9 lines] > >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.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Thomas G. Marshall - 14 Nov 2005 22:29 GMT Roedy Green coughed up:
> On Mon, 14 Nov 2005 18:19:17 +0000, Thomas Hawtin > <usenet@tackline.plus.com> wrote, quoted or indirectly quoted someone [quoted text clipped - 18 lines] > 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]...
 Signature Forgetthesong,I'dratherhavethefrontallobotomy...
Thomas Hawtin - 15 Nov 2005 07:03 GMT > Roedy Green coughed up: > [quoted text clipped - 23 lines] > > 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
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Roedy Green - 15 Nov 2005 07:13 GMT On Tue, 15 Nov 2005 07:03:41 +0000, Thomas Hawtin <usenet@tackline.plus.com> wrote, quoted or indirectly quoted someone who said :
>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"?
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Thomas Hawtin - 15 Nov 2005 09:14 GMT > On Tue, 15 Nov 2005 07:03:41 +0000, Thomas Hawtin > <usenet@tackline.plus.com> wrote, quoted or indirectly quoted someone [quoted text clipped - 7 lines] > 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,
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Thomas G. Marshall - 15 Nov 2005 15:22 GMT Thomas Hawtin coughed up:
>> On Tue, 15 Nov 2005 07:03:41 +0000, Thomas Hawtin >> <usenet@tackline.plus.com> wrote, quoted or indirectly quoted someone [quoted text clipped - 18 lines] > 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. [quoted text clipped - 5 lines] > [1] Assuming the static field is non-volatile and written from outside > of class initialisation and the constructor, Thomas G. Marshall - 15 Nov 2005 21:11 GMT Thomas Hawtin coughed up:
>> 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 [quoted text clipped - 3 lines] > 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.
Thomas G. Marshall - 14 Nov 2005 18:32 GMT mrandywarner@gmail.com 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 [quoted text clipped - 9 lines] > class C2 { > private Integer value; You need an actual instance here
value = new Integer(0);
> ... > public int getValue() { [quoted text clipped - 3 lines] > } > } 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.
 Signature "So I just, uh... I just cut them up like regular chickens?" "Sure, just cut them up like regular chickens."
Thomas G. Marshall - 14 Nov 2005 22:23 GMT Thomas G. Marshall coughed up:
...[rip]...
> If you did it your way, but made the embedded Integer "value" object > exposed: [quoted text clipped - 4 lines] > 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.
 Signature Forgetthesong,I'dratherhavethefrontallobotomy...
Thomas Fritsch - 14 Nov 2005 17:40 GMT > 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) > { [quoted text clipped - 3 lines] > } > }
> 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
 Signature "Thomas:Fritsch$ops:de".replace(':','.').replace('$','@')
Ian Pilcher - 14 Nov 2005 17:59 GMT > 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.
 Signature ======================================================================== Ian Pilcher i.pilcher@comcast.net ========================================================================
Chris Uppal - 14 Nov 2005 17:53 GMT > Am I correct? You are correct.
-- chris
Roedy Green - 14 Nov 2005 17:58 GMT On Mon, 14 Nov 2005 10:59:04 -0600, Ian Pilcher <i.pilcher@comcast.net> wrote, quoted or indirectly quoted someone who said :
>Am I correct? I think you are. You can see if there are any differences at all by decompilng both with Javap.
See http://mindprod.com/jgloss/disassembler.html
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
abrasivesponge@gmail.com - 14 Nov 2005 18:12 GMT > I would just like to confirm that my understanding of synchronized > methods is correct. I believe that the two code snippets below are [quoted text clipped - 26 lines] > > 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.
Free MagazinesGet 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 ...
|
|
|