aspose file tools*
The moose likes Threads and Synchronization and the fly likes Questions about the fixed Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Questions about the fixed "volatile" keyword" Watch "Questions about the fixed "volatile" keyword" New topic
Author

Questions about the fixed "volatile" keyword

Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10
Can anyone answer these questions:

1) Was the fix for volatile back-ported to 1.4 JVMs?

2) If the fix was not back-ported to 1.4 JVMs, is there an alternative idiom that can guarantee the same "happens-before" semantics (aside from standard synchronization)? Maybe something in the back-port of the Java 5 concurrency package?

3) Even more specifically, was the fix back-ported in IBM's 1.4 JVM (the one used in WAS 6.0)?

4) If code containing "volatile" is compiled using a 1.4 compiler, but is run on a 1.5 JVM, does the code execute with the fixed volatile semantics?

I know that volatile was broken before Java 5. I'm currently developing an application that needs to be able to run on both 1.4 and 1.5 JVMs, and I have a scenario in my code where the use of "fixed" volatile would be absolutely perfect.

I've seen on some earlier posts in this forum that using something like:

Map example = null;
synchronize(new Object()) {
example = new HashMap();
}

Can help create the same types of "memory boundaries" that the volatile keyword creates. Is this true?
[ January 25, 2008: Message edited by: Jim Hurne ]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[JH]: 1) Was the fix for volatile back-ported to 1.4 JVMs?

Um, I think some issues were fixed for 1.4, e.g. the notorious ineffectiveness of volatile for long and double values. But in general I would not trust volatile to do anything useful in 1.4.

[JH]: 2) If the fix was not back-ported to 1.4 JVMs, is there an alternative idiom that can guarantee the same "happens-before" semantics (aside from standard synchronization)? Maybe something in the back-port of the Java 5 concurrency package?

It's possible there is something in a back-port, but I doubt it. Prior to 1.5, synchronization was usually the only reliable solution to threading issues. Or immutability, I guess. (And even that had some issues.)

[JH]: 3) Even more specifically, was the fix back-ported in IBM's 1.4 JVM (the one used in WAS 6.0)?

No idea.

[JH]: 4) If code containing "volatile" is compiled using a 1.4 compiler, but is run on a 1.5 JVM, does the code execute with the fixed volatile semantics?

Yes. It's a JVM issue, not a compiler issue.

[JH]: I know that volatile was broken before Java 5. I'm currently developing an application that needs to be able to run on both 1.4 and 1.5 JVMs, and I have a scenario in my code where the use of "fixed" volatile would be absolutely perfect.

I've seen on some earlier posts in this forum that using something like:

Map example = null;
synchronize(new Object()) {
example = new HashMap();
}

Can help create the same types of "memory boundaries" that the volatile keyword creates. Is this true?


I believe so, yes. The sync block there obviously doesn't do any useful blocking of other threads, but it does force all variables to be refreshed before they're used again.


"I'm not back." - Bill Harding, Twister
Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10
If the idiom works, then could one fix the double-checked locking pattern? This doesn't seem right to me.

Example:



That seems too simple. Isn't it possible that an out-of-order write will still occur?

However, to clarify, I'm not actually attempting double-check locking in my code, as I'm not using the Singleton design pattern. However, my code is still susceptible to out-of-order writes.

What I am doing is initializing an immutable, non-singleton object and storing it in a static field. Multiple threads can (and will) access the static field and initialization code. Maybe an example would be best:



A couple of notes:

1) Creation of the object is expensive, thus the above code is an attempt to share the object with multiple threads.
2) I don't care if multiple threads get some "extra" copies of the immutable object, or if extra copies are created and discarded right away. Threads getting extra copies will not harm the execution of the application (the cost is only memory and some performance).
3) Because of #2, at first glance, it does not appear that the code needs synchronization.
4) However,the code is still vulnerable to out-of-order writes, and it IS possible for a thread to obtain a partially-constructed Immutable.

In Java 5, volatile would fix the problem. Is there anything I can do in Java 1.4, aside from synchronizing the entire getInstance() method?
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[JH]: That seems too simple. Isn't it possible that an out-of-order write will still occur?

Yes. You could have one thread see the value of instance as not null, but the thread that creates the instance is still creating it, or hasn't written its local data back to main memory yet. Yes, everything will sync mup again when the contstructing thread leaves the sync block(s), but inside the sync block there's still ambiguity about whether the static field "instance" gets written to main memory before the singleton instance data gets written. (In this case there is no instance data so it's a non-issue, but in general that's not the case.)

[JH]: 3) Because of #2, at first glance, it does not appear that the code needs synchronization.

Unfortunately there are potential problems besides extra copies. There's also the possibility that a thread will be able to get a reference to Immutable that isn't fully initialized. That's probably worse that merely getting extra copies - some fields may be null.

[JH]: In Java 5, volatile would fix the problem. Is there anything I can do in Java 1.4, aside from synchronizing the entire getInstance() method?

Yes, there's the initialization-on-demand holder idom. The sipmlest form (for a singleton) is like this:

The JLS guarantees that class Holder will be initialized once the first time getInstance() is called. This should be faster than synchronization.

Modifying this for your case shouldn't be difficult:
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 863
    
    1
Originally posted by Jim Hurne:
What I am doing is initializing an immutable, non-singleton object and storing it in a static field. Multiple threads can (and will) access the static field and initialization code. Maybe an example would be best:



A couple of notes:

1) Creation of the object is expensive, thus the above code is an attempt to share the object with multiple threads.
2) I don't care if multiple threads get some "extra" copies of the immutable object, or if extra copies are created and discarded right away. Threads getting extra copies will not harm the execution of the application (the cost is only memory and some performance).
3) Because of #2, at first glance, it does not appear that the code needs synchronization.
4) However,the code is still vulnerable to out-of-order writes, and it IS possible for a thread to obtain a partially-constructed Immutable.

In Java 5, volatile would fix the problem. Is there anything I can do in Java 1.4, aside from synchronizing the entire getInstance() method?


Well I suppose you could try something with ThreadLocal. Perhaps something like this:

(note: I've left in some java5-isms for readability. You would probably have to remove the generic and autobox stuff for 1.4.)

Whether the overhead of ThreadLocal would be worth it is your call.


bitguru blog
Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10
[JY]: Yes, there's the initialization-on-demand holder idom.


Now that is interesting. Are you suggesting that the "getting an Immutable before it is fully initialized" issue only applies to the first Immutable created? Thus, after the original assignment, all further assignments (caused by the last changed time being exceeded), are initialized and assigned atomically?

If the answer is yes, then that's a great, simple solution.

Another solution that I think may work is to use AtomicReference.
If I understand the Javadoc correctly, the Atomic classes have semantics similar to the volatile keyword.



I took a peak at the source for AtomicReference in the backport, and unfortunately, it uses synchronization. That seems to suggest that synchronization may be the only way to do this in Java 1.4. Interestingly, however, AtomicReference does not synchronize on the get() method. Just the set() method. It also uses the volatile keyword.
Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10
[BC]: Well I suppose you could try something with ThreadLocal.


This is also an interesting suggestion. In essence, you are using the double-check locking idiom, but in a ThreadLocal context. You also change the emphasis from loadable to the last changed timestamp.

I'm still trying to reason out whether or not this approach would work, or rather that it guarantees that a thread can not obtain a partially constructed Immutable.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[JH]: Are you suggesting that the "getting an Immutable before it is fully initialized" issue only applies to the first Immutable created?

No, I guess I overlooked that. The holder idiom works well for a lazily-loaded singleton (class initialization is guaranteed to happen before use of the field) but subsequent reinitializations don't have that guarantee. You'd need synchronization there. Never mind.

The ThreadLocal solution is interesting. One issue is that if you've got a thread pool of 100 threads, you'll initialize "loaded" 100 times. And then you'll end up reloading about 100 times (roughly averaged) whenever the lastChanged times get high enough. That may well be acceptable, or it may not.

As for the possibility of seeing an unfinished object (one whose initialization is not complete), I think you're safe there. Normally I am leery of attempts to sync only when writing an object, not when reading, as there's usually a loophole somewhere. But I think it's safe here. Some threads may see the old object even after a new one has been loaded, but that's probably OK. It should only be possible a relatively short time after the new object has been created - as long as your timeout period doesn't need to be [i]really[/i strict, I don't think it's much of a problem. But you should see either the old object or the new object, not some mix, and not an unfinished version of either.

The AtomicReference solution could work. I guess if the port uses synchronization on the set, then you should be safe from seeing an unfinished object - the sync barrier will guarantee that any thread that sees the new reference will also see a fully constructed object. I think.

Honestly though, I don't remember all the details of the old memory model. My general recollection is that synchronization was the one technique that was actually reliable prior to JDK 5, and that various complicated schemes to avoid synchronization usually ended up biting you in the butt. Doug Lea's backport of AtomicReference may work because he is more aware of just what are the limitations of volatile under JDK 1.4. But personally, I'd feel a lot more confident simply using synchronization to be sure. Do you have definite reason to believe that synchronization is a problem here? Many people have caused themselves a great deal of needless suffering by trying to avoid synchronization when they didn't have to. It's worth considering, I think.
[ January 27, 2008: Message edited by: Jim Yingst ]
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 863
    
    1
Originally posted by Jim Yingst:
[The ThreadLocal solution is interesting. One issue is that if you've got a thread pool of 100 threads, you'll initialize "loaded" 100 times. And then you'll end up reloading about 100 times (roughly averaged) whenever the lastChanged times get high enough. That may well be acceptable, or it may not.


You seem to have misread my code. Each thread has it's own timestamp object, which it uses to avoid synchronization. The synchronized block makes sure there is only one "loaded" object (or perhaps two, one referenced by "loaded" and one under construction).

Originally posted by Jim Hurne :
I took a peak at the source for AtomicReference in the backport


I thought AtomicReference was only in 1.5+, and hence not useful here. Has it indeed been backported?
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 863
    
    1
Originally posted by Jim Hurne:

[BC]: Well I suppose you could try something with ThreadLocal.

I'm still trying to reason out whether or not this approach would work, or rather that it guarantees that a thread can not obtain a partially constructed Immutable.


I just threw that code together, and I'm not a threading guru, so I don't guarantee it to work.

If it doesn't, I'm pretty confident there's some way to use a ThreadLocal correctly, a la something like this. The question is whether the overhead of ThreadLocal is less than that of single-checked synchronization´┐Żit may not be.
[ January 27, 2008: Message edited by: Brian Cole ]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[BC]: You seem to have misread my code. Each thread has it's own timestamp object, which it uses to avoid synchronization. The synchronized block makes sure there is only one "loaded" object (or perhaps two, one referenced by "loaded" and one under construction).

I see - I overlooked the second "if (now - when > 1000)" which prevents the excess loading I was imagining. It was clear there was only one two instances at a time, but I thought they were getting replaced more frequently. Nicely done.

My impression from limited testing and the statements of others is that ThreadLocal is faster that synchronization (which is itself pretty fast nowadays unless you're blocking waiting for a slow method). I think this handles al the issues nicely. The only downside I see is that the ThreadLocal would take up a little more memory than other methods, since there's a per-thread copy of each timestamp. But that's pretty trivial.

As a matter of API design, I would prefer not to see it extend ThreadLocal directly, as that's an implementation detail that users shouldn't know about. And there's really no need for a Manager class separate from the Immutable class:

[ January 27, 2008: Message edited by: Jim Yingst ]
Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10

[BC]: I thought AtomicReference was only in 1.5+, and hence not useful here. Has it indeed been backported?


You bet. In fact, the entire java.util.concurrent package has been backported. The backport is based on Doug Lea's code that he submitted for JSR 166, and is maintained by Dawid Kurzyniec. You can read more about the project here.

When I found the backport, I was pretty excited. We have a lot of clients still using Java 1.4, but at least with the backport, we can use some of the goodness of Java 5.
Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10

[JY]: Do you have definite reason to believe that synchronization is a problem here? Many people have caused themselves a great deal of needless suffering by trying to avoid synchronization when they didn't have to. It's worth considering, I think.


You raise a very good point. I actually don't know if synchronization would be a bottle-neck in this particular case, as I haven't been able to test it.

One could reason that synchronization isn't going to be much of a bottle-neck since most of the time, the code will only evaluate an if statement (which will evaluate to false most of the time) and a return of a reference variable. That isn't exactly a long-running piece of code. So even if 100 threads are stacked up waiting, they won't have to wait for very long.

I like the ThreadLocal solution, but the basic synchronization solution is a bit simpler and thus easier for someone else to understand. I'm going to try the synchronization approach first, and if we find it to be a performance issue, then we'll switch to the ThreadLocal solution.

Thanks for your help, this has been an interesting discussion.

For completeness, the sychronized solution looks something like this:

Chris Hurst
Ranch Hand

Joined: Oct 26, 2003
Posts: 420
    
    2

Sorry new to this thread and its a big one ;-) but just in case anyone else didn't mention this (i've done a quick scan of the text)....

Map example = null;
synchronize(new Object()) {
example = new HashMap();
}

Can help create the same types of "memory boundaries" that the volatile keyword creates. Is this true?

I believe so, yes. The sync block there obviously doesn't do any useful blocking of other threads, but it does force all variables to be refreshed before they're used again.


There is an issue I believe with this trick in Java 6+ in that the your memory barrier can be optimized away as its a side effect of synchronization and the JVM can see as your variable is local that no other thread can possibly synchronize on it and therefore it can be removed !! eek ! (I'vce seen this noted on other sites but I haven't tested this yet myself)


"Eagles may soar but weasels don't get sucked into jet engines" SCJP 1.6, SCWCD 1.4, SCJD 1.5,SCBCD 5
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[B][JH]:
[/B]
If loaded is null, then synchronized(loaded) will throw a NullPointerException. It would probably be simplest to synchronize instead on Immutable.class, or on some privately-held lock object.
[ January 28, 2008: Message edited by: Jim Yingst ]
Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10
[JY]: If loaded is null, then synchronized(loaded) will throw a NullPointerException.


Very true. What I actually ended up doing was using ReentrantLock instead of a synchronized block:



And as you pointed out earlier, all of this could be in the Immutable class itself. However, I have a few reasons in my project to have this code elsewhere. One reason is that the Immutable class can be instantiated in other ways (it has a public constructor), and the other reason is that Immutable is already a fairly large class, so separating out this "loading" code into another class makes things a bit easier to maintain.
Jim Hurne
Greenhorn

Joined: Nov 19, 2007
Posts: 10
[CH]: There is an issue I believe with this trick in Java 6+ in that the your memory barrier can be optimized away...


Thanks for the info. I cannot say that I'm terribly surprised. That's actually why I asked about the idom, as it didn't give me any warm fuzzes when I first learned of it.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
That's an interesting thought. I suppose it comes down to, how well did Sun's engineers obey the rules during this optimization? Escape anaylsis can allow them to remove synchronization in cases where it can be proven to have no effect, but memory flushing is an effect. I suppose the correct thing for them to do would be to remove the actual acquisition of a lock, but retain the memory flushing. Assuming that's possible. After all, losing the memory flushing does violate the JLS here. While it's certainly possible that this happens, I think it's also possible that Sun's engineers remembered to obey the rules here. It would be interesting to learn more details of just what happens in escape analysis.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
OK, looks like I oversimplified my interpretation of the JLS rules here. As Brian Goetz points out:
The Java Memory Model says that one thread exiting a synchronized block happens-before another thread enters a synchronized block protected by that same lock; this means that whatever memory operations are visible to thread A when it exits a synchronized block protected by lock M are visible to thread B when it enters a synchronized block protected by M, as shown in Figure 1. For synchronized blocks that use different locks, we cannot assume anything about their ordering -- it is as if there was no synchronization at all.

So the synchronized(new Object()) trick has no guaranteed effect at all then, since no other threads can sync on the same object.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Questions about the fixed "volatile" keyword