• 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

Confused on Thread Publication / Synchronization

 
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi guys, been reading concurrency in action and had a couple of questions.



The book says that since this class is immutable it is threadsafe since there is no modification of the state(stooges).
What I'm confused on is this. What if multiple threads were to call the isStooge(String name) method simultaneously. What happens?




The book says this is not thread safe? Why? What does it mean it's not properly published?




Same thing with this one. What's wrong with it? What if multiple threads call assertSanity().

Thank you guys



 
Ranch Hand
Posts: 65
Netbeans IDE Eclipse IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Sorry, where do you get that Immutable annotation?

2nd and 3rd code block is not thread safe because their methods are not synchronized.
 
Ranch Hand
Posts: 258
2
IntelliJ IDE Spring Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
For the first case, class ThreeStooges does not have method to modify the content of stooges.
It only has isStooge method which check if name is contained inside stooges (read only).
Since, it is a read only action, and no one else could change the content of stooges once initialized, it is fine for concurrent access.
 
Greg Bag
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Raymond Tong wrote:For the first case, class ThreeStooges does not have method to modify the content of stooges.
It only has isStooge method which check if name is contained inside stooges (read only).
Since, it is a read only action, and no one else could change the content of stooges once initialized, it is fine for concurrent access.



Interesting... So concurrent read only is mostly thread-safe. What about code #2 and #3?
 
Rancher
Posts: 1090
14
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Greg Bag wrote:What about code #2 and #3?



There are many ways in which the state of a HolderObject/Holder object can be changed after it is constructed. Hence it is not immutable. HolderObject is worse than Holder cause even the construction is not complete till the initialize method is called. Nothing stops you from calling the initialize on a HolderObject more than once thereby changing its state. You don't even require extra threads for that. That is not what immutable objects allow.

Some of the other simplest ways that I can think of ( and I think there are going to be many ) to change the state of the object after construction are -

1. Both the above classes can be extended. A subclass can always provide setter methods. A subclass can always leak the this reference even before the construction is complete.
2. None of the fields that constitute the state of the object are final and you have methods that can be overridden.

These are the simple ways that I can think of (but I guess there are far too many ways ) in which you can change the state of a HolderObject/Holder object.

About the following -

Interesting... So concurrent read only is mostly thread-safe.


I don't think so, but I am not sure and I think it has many ifs and buts applicable and it's way too complicated than it sounds. So I will wait to hear what the experts have to say to that. :-)

Chan.


 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Chan Ag wrote:

HolderObject is worse than Holder cause even the construction is not complete till the initialize method is called. Nothing stops you from calling the initialize on a HolderObject more than once thereby changing its state. You don't even require extra threads for that. That is not what immutable objects allow.



That is not right. Actually a HolderObject has mutated the first time you call it's initialize method. initialize method isn't a part of the construction process. It's a method that is separately invoked on an already constructed object to initialize the Holder it is encapsulating.
 
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Chan Ag wrote:

Interesting... So concurrent read only is mostly thread-safe.


I don't think so, but I am not sure and I think it has many ifs and buts applicable


Pure read-only tasks are thread-safe, a read won't interfere with another read as long as you know there is no state change involved. The trick is understanding what you are reading. If the variables were assigned in the construction of the object and those variables can't be changed (immutable) then you can be sure that you are reading the data you want. Otherwise, in order to read data that has been written, there must be a synchronization barrier crossed (such as the end of one synchronized block and a start of another). The end of construction/initialization actually provides such a barrier which is why setting all your variables in initializers and the c'tor works.

The pesky part of inter-thread data sharing is the writes - when you write data you need to think about what values were written in what order, and relative to other values that were written. Then your reader tasks need to worry about what values are visible and safe to read. When reads and writes are mixed you need to add synchronization barriers to make sure you get consistency when you need it, or the most up-to-date value when you need that. But when there are no writes involved, the reads are a whole lot easier (which is why immutable objects are so important and should be your strategy of choice whenever possible).
 
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Greg Bag wrote:

Raymond Tong wrote:For the first case, class ThreeStooges does not have method to modify the content of stooges.
It only has isStooge method which check if name is contained inside stooges (read only).
Since, it is a read only action, and no one else could change the content of stooges once initialized, it is fine for concurrent access.



Interesting... So concurrent read only is mostly thread-safe. What about code #2 and #3?



Chan Ag wrote:
About the following -

Interesting... So concurrent read only is mostly thread-safe.


I don't think so, but I am not sure and I think it has many ifs and buts applicable and it's way too complicated than it sounds. So I will wait to hear what the experts have to say to that. :-)



Great catch Chan !!

Yes, read only operations does *not* necessarily mean that it is thread safe. There could be state that changes, and hence, the reads are order dependent; or the state changes could conflict between thread calls; etc.

Having said that, if you look at the JavaDoc for the HashSet class, you will notice that multiple reads (and only reads) are thread safe. There is a mention that reads do not change the structure of the data, and is allowed without synchronization. And as for the rest of the method, there are no sharing of any other data besides the hashset, so as stated in the original post, the first case is thread safe.

Hope this helps,
Henry
 
Ranch Hand
Posts: 59
6
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


This is still not thread-safe even if there are no subclasses or multiple threads accessing it at the same time, because n is not safely published. This can throw an AssertionError if one thread creates a Holder, and then later another thread calls assertSanity. Because there are no memory barriers between the writing and the reading, the reading thread could see different values of n each time it's read. One possibility is that the write to n could become visible to the other thread after the first n is read but before the second.

One solution here is to make n final. The initialization of final variables is guaranteed to happen before the constructor has returned so any thread that sees the Holder object after it's been created will also see the new value of n and only that value.
 
Steve Luke
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Sresh, great point on distinguishing the safety of a final field versus the non-final field given in the example. Have a cow

 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks a lot, All.

Each of your responses has given me a better perspective on immutability ( if what I've understood is right ). I know there is still a lot more to know on this and it's still sort of complicated ( I haven't read the language specifications--reordering of instructions' rules, happens' before rules are difficult to remember also ( at least I find them so )), but your responses have given me some easy to remember rules ( I hope I wont forget them ). Thank you.

I will still go for easy things ( immutable objects or synchronization ) when in doubt. :-)

Chan.
 
Master Rancher
Posts: 4806
72
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The final is also important in the very first example, with the HashSet:

Without final here, the HashSet would not be considered safely published upon completion of the ThreeStooges constructor, and there would be no guarantee that all the add() calls had completed in the constructing thread, before some other thread calls isStooge(). Without a final stooges field, ThreeStooges cannot be considered an immutable class - even if it has no accessors and the class itself is final. The field needs to be final too.
 
Greg Bag
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator



Guys I'm still confused on why this is not published correctly. Can someone give me a scenario of why the final is needed here? An example with 2 threads would be good. Also, what are the rules to publishing something successfully? What should i follow?
Also another thing, let's say Thread A calls the setter method and sets value to 5. Since it's synchronized, there is no corruption and visiblity is there. So why would get() here have problems? Since the setter already set the value, how can the get() obtain a stale/inconsistent value?

 
Rancher
Posts: 989
9
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If two threads are executing, one is calling the get method while the other is calling the set method. What result would the one calling the get method find?
 
Steve Luke
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Greg Bag wrote:Also, what are the rules to publishing something successfully? What should i follow?

The rules are in the Java Memory Model, we could summarize but it would be lacking completeness. The link defines what guarantees can be made and when, anything else is a possible race condition.

Also another thing, let's say Thread A calls the setter method and sets value to 5. Since it's synchronized, there is no corruption and visiblity is there.

The visibility guarantee is only guaranteed when there is a 'happens-before' relationship - when the set happens-before the get. The link defines when the happens-before relationship exists. It doesn't exist just at the end of a synchronized block, it needs the end of a synchronized block and the start of another on the same object. And happens-before isn't about simple timing, it is about re-ordering and when memory is guaranteed to be published. So even if the set occurs well before the get, since there is no happens-before relationship (no synchronization barrier) the get operation still may not see the set operation.
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Steve Luke wrote: The rules are in the Java Memory Model, we could summarize but it would be lacking completeness. The link defines what guarantees can be made and when, anything else is a possible race condition.



Thanks, Steve. This topic still belongs to Greg and I'm not trying to hijack it. But I couldn't stop myself from thanking Steve for that wonderful link.
 
Greg Bag
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Guys I'm slowly understanding how the whole process works. Some additional questions. Concurrency is the only topic in java that baffles me lol.



1) What if final keyword was missing on the hashset? My assumption is that it is not properly published and other threads can see a mid-constructed object.

2) Lets say synchronized is missing on the containsPerson. Thread A calls addPerson(new Person("John")); 5 seconds later, Thread B calls containsPerson(new Person("John")), will it actually see the updated Person("John") object from thread A?
My assumption is no because even though the addPerson is synchronized, the containsPerson, when it searches the set, can see the previous myset object which didn't include John. So a stale or incomplete set. So synchronization on the
containsPerson is mandatory for visibility.


3) Replace the code with the following. My assumption is that writes only occur in the constructor. After the constructor finishes, it gets properly published and no other threads can see the mid-constructing of the mySet object because of the final keyword.
Since there are no writes other than the constructor, there will be no visibility issues if you call containsPerson. So in my opinion, synchronized can be omitted on the getter.



4) What changes would make this class not properly published?

5) What if Person is mutable? If a thread updates a Person, will all other threads see the updated Person in the hashset? Anything else I should look out for?



Also overall in general the only thing that really confuses me is proper publication. What is the best way to publish a mutable class? Is the following class I wrote properly published? Thread-safe?



So this is a class that has both immutable and mutable fields. Host is immutable and guests are mutable.

My assumptions:
1) Both host and guests should be final for it to be properly published. Why?
2) getHost() does not need to be synchronized because it's created only once in the constructor and never changed. So no visibility problems.






 
Steve Luke
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Greg Bag wrote:1) What if final keyword was missing on the hashset? My assumption is that it is not properly published and other threads can see a mid-constructed object.

2) Lets say synchronized is missing on the containsPerson. Thread A calls addPerson(new Person("John")); 5 seconds later, Thread B calls containsPerson(new Person("John")), will it actually see the updated Person("John") object from thread A?
My assumption is no


It isn't a yes/no answer, it isn't guaranteed to see the new Person, but it may see it or it may not depending on lots of things, and it may see something in between (like the count of objects include the new Person but not be able to see the Person in the set and so throw a non-obvious exception...) It is uncertain.

3) My assumption is that writes only occur in the constructor. Since there are no writes other than the constructor, there will be no visibility issues if you call containsPerson. So in my opinion, synchronized can be omitted on the getter.


If we assume you meant mySet.add(new Person(...)) instead of mySet.addPerson(...) in that code, then yes. But if you meant addPeson(...) then the answer is unclear because we don't see that method.

4) What changes would make this class not properly published?

I think you covered most of them previously - remove the final keyword, make a setter method, make the containsPerson() method modify the set somehow. Note, the person you get in could be modified while you search, which could affect the outcome of the search but it wouldn't affect the safety of the set.

5) What if Person is mutable? If a thread updates a Person, will all other threads see the updated Person in the hashset?


No, only the set is protected. If the Person is mutable, to make safe use of the PersonSet you would need to be in total control of the Person instances in the set. In your code, someone can add a Person to the set, to make it safe you would need to make a copy of the Person and put it in your set so any changes made by the outside world do not affect the internal state. Similarly, if you have a way of getting a Person out of the set, then you need to make a copy of the Person that is in the set and give out the copy, so if someone changes the Person outside your control then it does not affect the state of the set.

In your updatePerson method: I am not sure it will compile because it has two Person p references, I forget if that is legal (and the inner one hides the parameter) or not. Either way, the idea is that you are updating the instance that is in the set, not putting the value from outside into the set, which is the correct way to do it. On a technical side, though, you should remove the Person from the set, make the change, then add it back to the set because any change could modify its hashcode, and if it does then the Object could be impossible to find later on. You need to take it out and put it back in to make sure the new hashcode is used for storing the Object in the set.

Also overall in general the only thing that really confuses me is proper publication. What is the best way to publish a mutable class? Is the following class I wrote properly published? Thread-safe?


No, for reasons discussed earlier in this thread and for reasons earlier in this post.

So this is a class that has both immutable and mutable fields. Host is immutable and guests are mutable.


Are you saying Person is an immutable class or are you saying you don't change the host reference? They are very different things.

My assumptions:
1) Both host and guests should be final for it to be properly published. Why?


Discussed earlier in the thread, and defined in the JLS link posted previously.

2) getHost() does not need to be synchronized because it's created only once in the constructor and never changed. So no visibility problems.


Only if the host is made final. And if Person is mutable then it needs to provide a defensive copy as the returned object to be safe.






 
Sresh Rangi
Ranch Hand
Posts: 59
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In one of these example, there are mutations to the object after the final variable is set. I don't think they are guaranteed to be visible. Consider two examples:

Example 1:


Example 2:


In example 1, the set is mutated after the instance variable is set. We have actions:

a) Thread1: - mySet initialization
b) Thread1: - set add
c) Thread2: - set contains

The happens-before relationships are: hb(a, b) and hb(a, c). This allows the orderings a -> b -> c and a -> c -> b.

In example 2, the set is mutated before the instance variable is set. We have actions:

a) Thread1: a - set add
b) Thread1: b - mySet initialization
c) Thread2: c - set contains

The happens-before relationships are: hb(a, b) and hb(b, c). This only allows a -> b -> c.

So reading a final variable only guarantees visibility of actions that happen before it's set.
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Sresh Rangi wrote:In one of these example, there are mutations to the object after the final variable is set. I don't think they are guaranteed to be visible. Consider two examples:

Example 1:


Example 2:


In example 1, the set is mutated after the instance variable is set. We have actions:

a) Thread1: - mySet initialization
b) Thread1: - set add
c) Thread2: - set contains

The happens-before relationships are: hb(a, b) and hb(a, c). This allows the orderings a -> b -> c and a -> c -> b.

In example 2, the set is mutated before the instance variable is set. We have actions:

a) Thread1: a - set add
b) Thread1: b - mySet initialization
c) Thread2: c - set contains

The happens-before relationships are: hb(a, b) and hb(b, c). This only allows a -> b -> c.

So reading a final variable only guarantees visibility of actions that happen before it's set.



Mike Simmons wrote:The final is also important in the very first example, with the HashSet:



Without final here, the HashSet would not be considered safely published upon completion of the ThreeStooges constructor, and there would be no guarantee that all the add() calls had completed in the constructing thread, before some other thread calls isStooge(). Without a final stooges field, ThreeStooges cannot be considered an immutable class - even if it has no accessors and the class itself is final. The field needs to be final too.



I'm slightly confused here and I'm hoping you'd want to correct me so I get this answer once and for all ( cause it has kind of confused me every time I have tried to understand it ). So are you (both? ) saying that the three adds in the Greg's first example are not guaranteed to show at the time the ThreeStooges constructor returns object is published ( it's reference is available to other threads/same thread)? I mean are you saying that at the time the constructor returns ThreeStooges object is available to other threads/same thread, it is guaranteed that stooges will not be null but the three adds have completed is not guaranteed?

Or am I not getting what one or both of you are saying? Please help.

Chan.
 
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

I'm slightly confused here and I'm hoping you'd want to correct me so I get this answer once and for all ( cause it has kind of confused me every time I have tried to understand it ). So are you (both? ) saying that the three adds in the Greg's first example are not guaranteed to show at the time the ThreeStooges constructor returns? I mean are you saying that at the time the constructor returns, it is guaranteed that stooges will not be null but the three adds have completed is not guaranteed?




If your example 1 is ...



At constructor exit another thread is guaranteed to see stooges initialised and its contents (as changed within the ctr the add's).

Caveats : Only because stooges is final and its this pointer never escapes the constructor . Stooges is guaranteed null at creation and initialised at ctr exit. The happens before ordering on the adds is a special side effect of the final guarantee. Indeed the JVM could (not guaranteed) use a store store barrier at ctr exit to implement this.


The usage model for final fields is a simple one. Set the final fields for an object in that object’s
constructor. Do not write a reference to the object being constructed in a place where another
thread can see it before the object’s constructor is finished. If this is followed, then when the
object is seen by another thread, that thread will always see the correctly constructed version of
that object’s final fields. It will also see versions of any object or array referenced by those final
fields that are at least as up-to-date as the final fields are.

- JSR 133
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you, Chris.
 
Greg Bag
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Sresh Rangi wrote:In one of these example, there are mutations to the object after the final variable is set. I don't think they are guaranteed to be visible. Consider two examples:

Example 1:


Example 2:


In example 1, the set is mutated after the instance variable is set. We have actions:

a) Thread1: - mySet initialization
b) Thread1: - set add
c) Thread2: - set contains

The happens-before relationships are: hb(a, b) and hb(a, c). This allows the orderings a -> b -> c and a -> c -> b.

In example 2, the set is mutated before the instance variable is set. We have actions:

a) Thread1: a - set add
b) Thread1: b - mySet initialization
c) Thread2: c - set contains

The happens-before relationships are: hb(a, b) and hb(b, c). This only allows a -> b -> c.

So reading a final variable only guarantees visibility of actions that happen before it's set.



So which one here is thread-safe? The first or second class or both?
 
Chris Hurst
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Quick answer :
They are both thread safe.

Long answer:

The bit that was missing from the previous discussions is a final is not set in happens before ordering terms where its set in non volatile single thread terms :-) i.e. when it is guaranteed to have happened in single threading terms is not when it is guaranteed to have happened for all other threads in visibility (happens before ordering) terms.

So when you set a final variable in a ctr its only guaranteed visibly set for THAT thread until the ctr exits then all threads (volatile readers) are guaranteed to see it eg if you leak the this pointer to another thread (ie set it to a global or pass it as a parameter eg register a listener) before the ctr exits it can see the final unset eg 0 / null if your not careful (just don't ever do this).

It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

- JSR133

So its like the set of the final always occurs at the end of the ctr regardless of how you place it in terms of what OTHER threads can guarantee to observe, this special action for finals has an additional guarantee (above) that takes care of the adds. When you publish the final at ctr exit you publish the modifications that happen before this (those referenced by the final). Finals and ctrs are special behaviour and the example implementation from the JSR was a store/store barrier on ctr exit (cache flushes+no code reordering across the barrier)

Its not the final variable set that's magic but the constructor exit in simpler terms that's when the final obeys happens before ordering, its not a volatile.

I appreciate my answer may be confusing but it is quite a tough topic ;-)
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic