• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Advanced Java Memory Model question

 
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am working on a project that requires the use of Java 1.1.8 (don't ask...
we are stuck there). Old versions of Java (pre JSR-133) had some memory
model issues that I need to fully understand so that we write correct
multi-threaded code.

The following events will happen in order from top to bottom. The question
(which I will repeat below) is, is Thread C guaranteed to see the correct
contents of X (i.e. it is a question of visibility)?


Thread A
--------

1) Creates an object X which holds immutable data
2) Places X on message queue Q0 (thereby acquiring and releasing internal lock L0)

Thread B
--------

1) Fetches object X from message queue Q0 (thereby acquiring and releasing lock L0)
2) Places X on message queue Q1 (thereby acquiring and releasing internal lock L1)

Thread C
--------

1) Fetches object X from message queue Q1 (thereby acquiring and releasing internal lock L1)
2) Inspects the immutable data fields of object X (no synchronization is performed)



My reading of Doug Lea's Java Memory Model page (http://gee.cs.oswego.edu/dl/cpj/jmm.html) is that Thread B is guaranteed to see the up to date data of X because of the pairing of the release and acquisition of lock L0. Thread B, however, does not care about the contents of X and does not inspect it (i.e. may not force that area of memory to be read into local cache).

The question is, is Thread C guaranteed to see the correct contents of X? It was passed the object by a thread that was guaranteed (if it choose to look) to see the correct contents.

I ask the question because the guarantee is usually quite specific, there needs to be a pairing of a lock released by a thread that modified memory and an acquisition of the *same lock* by a thread that is reading that memory.

In Java 5.0+ we are fine by the "happens before" guarantee but that was introduced by JSR 133. Are we still fine (barring buggy JVMs) in Java 1.1.8?
 
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Interesting post, I was waiting for some one to be brave enough to respond first, but as no one else has bitten, I'll see if this starts a debate ...

Answer : Maybe ;-)

First off your probably running on an OS / processor with a strong memory model and a green threaded JVM (Java 1) so I wouldn't worry too much though even all that won't keep your thread safe (eg. byte code reordering)

Looking at your example its hard to see the advantage you gain post JSR133 as you just have clear locks with no use of volatile, final, static etc etc .

However next point particularly as your on Java 1 you must be clear on thread immutable not just immutable eg. some early forms of String were immutable but not thread immutable.

Next examining your thread flow if as you describe you have proper synchronization between the threads my next question is how are you passing the object between queues deep copy, reference etc.

I'll look at reference first , thread B's read writes (1,2) are guaranteed to happen before A)'s and C)'s after B's all cool but what about the bits and bytes on the end of that reference well in theory they were published by A) guaranteed to be available to B) and subscribed to correctly by C) (Happens before ordering) but I'd have to question your objects implementation ie. true immutability etc.

Sooo what is Doug going on about when he mentions sync on the same object, well if he didn't say that as an example (this is just an example issue) it would be tempting to think of entering a sync'ed block as a 'memory barrier' and some people have, simplest example I can think off (I'm sure some one else will have a better one).


I'm going to do a sync in two threads but not on the same object (bad me) ..

Thread A)


Thread B


Problem is synchronization was never intended as a memory barrier it just just can do it if it needs to, in this case Java (6,7) can see no other thread can sync on o or p so the synchronization can optimize out along with your intended memory barrier 'eek' , i.e. the code is as if the sync never happened no 'happens before ordering'.
 
Patrick Lahey
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Firstly, and most importantly, thanks for responding!

The strong memory model/green (i.e. non-native) threaded argument is probably
true but won't help me sleep better at night :-) We do hope that one day
we can transition to PBP 1.1 which, I believe, moves us into native thread
land (probably depends on the underlying hardware and OS...).

As I see it, there would be two advantages of living in a post JSR133 world.
The first is the "initialization guarantee" which would address your
immutable vs. thread immutable concern (its my main concern as well...).
The second is that I can depend on "happens before" reasoning and guarantees
since, as I understand it, happens before was introduced in JSR133.

I am aware that smart and modern JVMs can optimize locks away. I am dealing
with locks that are guaranteed to be necessary. What I really need to get
a handle on is, how much can I rely on the simple conceptual model that is
typically given when discussing visibility issues (i.e. a lock release
flushes out the contents of "thread local memory" to main memory and a
lock acquire invalidates "thread local memory" and forces it to be
loaded in from main memory).

If the standard conceptual model is essentially accurate, as long as I can
guarantee a happens before relationship (which I can here), it should
not matter if a different lock is acquired than was released (as least
as far as I have been able to determine).
 
Chris Hurst
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The quick answer is provided you use synchronization a lot you can achieve thread safety in Java 1 and your code outline looks on the right track however you will end up using synchronization a lot more than if you live in a nice post JSR-133 world.

I'm not entirely sure what you mean by "initialisation guarantee" you can make use of a post JSR-133 world to do stuff like declare static , final, volatile objects such that the initialization of there reference will always happen before the initialization of the referant's member variables which you can't post JSR-133 you'ed need to use blocks synched on a common object prior to JSR-133 to achieve the same effect.

If an object is 'immutable' but not 'thread immutable' the fact its initialized ok may not save you depends on their immutable definition, historically the String class as an example had issues with this. Imagine you have a class where although the state it presents to the outside world is always the same it might think it can better optimize its internal representation at a later date. Consider intern -ing strings, a String (stupid, bad version) might try to move from being 'cat' to say being the first three letters of 'catastrophe' behind the scenes ie. it can do a better intern later in the program run, this kinda thing can seem like a good idea but threads can effectively see the internal state of your immutable object and if the state change is not atomic which it won't be in this case another thread can see it in a different state. Your immutable object isn't thread immutable, it depends on the strict definition of immutable.

Doug's talks are keen on pushing us away from the concept of flushing caches \ memory barriers and to happens before ordering for reasons like the one I illustrated but that was just an example I think others may come in round byte code re ordering and instructions entering \ exiting synchronization blocks, Dougs 'roach motel ordering' comes into play in that things can enter easily but seldom leave. All these issues can be averted using appropriate synchronization on common objects even in Java 1 you just may need a lot more of it.
 
reply
    Bookmark Topic Watch Topic
  • New Topic