• Post Reply Bookmark Topic Watch Topic
  • New Topic

unsafe publication problem  RSS feed

 
Andrew Cane
Ranch Hand
Posts: 91
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
could someone show me an example where the following codes will cause problem:



How would the holder appear to other thread in an inconsistent state? how is this categorized as improper publication?



How is it possible that assertSanity will throw AssertionError? sample case or code that would fail please?



1. how does "this" reference in this code escape?
2. could anyone show me an example where the supposedly escaped "this" reference will cause any problem?

I really can't wrap my head around these "problematic" code as I'm just beginning to look at synchronization.
Thanks.
 
Henry Wong
author
Sheriff
Posts: 22866
119
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andrew Cane wrote:


1. how does "this" reference in this code escape?
2. could anyone show me an example where the supposedly escaped "this" reference will cause any problem?



Anonymous inner classes, when instantiated in a constructor, has the this variable as its outer class. So, in this case, the inner class instance, and hence, possible access to outer class components, is passed to an external method. This means that the external method may have access to the this variable, before construction is complete.

Andrew Cane wrote:
I really can't wrap my head around these "problematic" code as I'm just beginning to look at synchronization.


This has nothing to do with synchronization. This is just a case where the this variable leaked -- given access to other code before construction has completed. And there is nothing that says that it is problematic -- it could just be fine.

Henry
 
Henry Wong
author
Sheriff
Posts: 22866
119
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andrew Cane wrote:
How would the holder appear to other thread in an inconsistent state? how is this categorized as improper publication?



How is it possible that assertSanity will throw AssertionError? sample case or code that would fail please?



I don't see how the AssertionError can be thrown either.

Henry
 
Andrew Cane
Ranch Hand
Posts: 91
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


That's what the book says about the Holder class. Perhaps you could elaborate more about this?

As for the anonymous inner class, could you please show me a code that describes this condition? I rarely use inner class, let alone in a constructor. lets use the example, or any example you prefer. I just need to see how "this" reference escaped. Thanks


[HENRY: Added line breaks, so that topic is more readable]
 
Maxim Karvonen
Ranch Hand
Posts: 121
12
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andrew Cane wrote:How would the holder appear to other thread in an inconsistent state? how is this categorized as improper publication?
How is it possible that assertSanity will throw AssertionError? sample case or code that would fail please?


It really depends on other code which uses Holder. It may be either a safe publication or unsafe one. For example, it is unsafe in the following example:

You may add some delays in threads before accessing holder, but it is not important. And it is not guaranteed that this program _will_ throw AssertionError. It _may_ throw it under some JVM implementation and in some circumstances or it may always work. Problem is that there is no happen-before relationship between writing the field in the Holder constructor and reading it in assertSanity method. Absence of the happens-before relation is pretty sufficient to have strange results (and you even may get 42 on the left side of the equality check and 0 on the right side!) in this case.

Anyway, there are non-formal (and non strict) explanation how this may happen. Object creation is not an "atomic" process. It consists of object creation, variable initialization and assignment to a host. It may be described as

And this may be optimized by the JVM to

This is perfectly legal in current java memory model unless some synchronized operations (explicit synchronization, volatile reads, some synchronized actions) prevents it. So in other threads you may see 0 as a value of holder.n (and it may change over time). Your example has a problem which is very similar to a double checked locking. You may read on it here, here and just google for "java double checked locking". Almost all these explanations use "reordering" metaphor which is somewhat far from actual java memory model. But at the same time "reordering" may be a way easier to understand that "happens-before" relationship.
 
Henry Wong
author
Sheriff
Posts: 22866
119
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Maxim Karvonen wrote:
Andrew Cane wrote:How would the holder appear to other thread in an inconsistent state? how is this categorized as improper publication?
How is it possible that assertSanity will throw AssertionError? sample case or code that would fail please?


It really depends on other code which uses Holder. It may be either a safe publication or unsafe one. For example, it is unsafe in the following example:

You may add some delays in threads before accessing holder, but it is not important. And it is not guaranteed that this program _will_ throw AssertionError. It _may_ throw it under some JVM implementation and in some circumstances or it may always work. Problem is that there is no happen-before relationship between writing the field in the Holder constructor and reading it in assertSanity method. Absence of the happens-before relation is pretty sufficient to have strange results (and you even may get 42 on the left side of the equality check and 0 on the right side!) in this case.

This is perfectly legal in current java memory model unless some synchronized operations (explicit synchronization, volatile reads, some synchronized actions) prevents it. So in other threads you may see 0 as a value of holder.n (and it may change over time). Your example has a problem which is very similar to a double checked locking. You may read on it here, here and just google for "java double checked locking". Almost all these explanations use "reordering" metaphor which is somewhat far from actual java memory model. But at the same time "reordering" may be a way easier to understand that "happens-before" relationship.


While the "happens-before" and the "reordering" are both good arguments... I believe we also have to remember that the new operator won't return the object, until the construction has completed. And since there is no leaking of the this reference in the constructor of this example, there should be no way to get an assert error. What can happen is likely a null pointer error, if the thread that is calling the assertSanity() method is called before construction has completed. However, if the other thread doesn't get an NPE, the holder object should have been guaranteed to have completed construction.

Henry
 
Henry Wong
author
Sheriff
Posts: 22866
119
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andrew Cane wrote:
As for the anonymous inner class, could you please show me a code that describes this condition? I rarely use inner class, let alone in a constructor. lets use the example, or any example you prefer. I just need to see how "this" reference escaped. Thanks



The concept is incredibly simple -- if it is possible for the this reference to be seen before the constructor completes, then it has leaked. One possible way is to have the variable be passed to some external function, such as this...



Another is to have it exposed in some variable somewhere, such as this...



In both cases, it is possible for some code (either in the same thread or different thread) to see the instance before construction has completed.... meaning the this variable has leaked.

Henry
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andrew, please QuoteYourSources.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Henry Wong wrote:...I believe we also have to remember that the new operator won't return the object, until the construction has completed. And since there is no leaking of the this reference in the constructor of this example, there should be no way to get an assert error.

Since n is not final then there is:

From the JLS section 17.5:
JLS section 17.5 wrote:Example 17.5-1. final Fields In The Java Memory Model

The program below illustrates how final fields compare to normal fields.


The class FinalFieldExample has a final int field x and a non-final int field y. One thread might execute the method writer and another might execute the method reader.

Because the writer method writes f after the object's constructor finishes, the reader method will be guaranteed to see the properly initialized value for f.x: it will read the value 3. However, f.y is not final; the reader method is therefore not guaranteed to see the value 4 for it.
 
Maxim Karvonen
Ranch Hand
Posts: 121
12
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Henry Wong wrote:I believe we also have to remember that the new operator won't return the object, until the construction has completed.


Steve already answered on this. It's only true for final fields or only for the thread performing an initialization (single-threaded flow). Only final fields (and all happens-before effects) are definitely "written" before "new" operator returns. And exactly this kind of reordering is why double checked initialization is broken. All "double checked locking" fixes establish happens-before relationship between a read (which observed non-null write) with that write.

And this is what I warned topic starter for. "Reordering" and other "code-rewriting" metaphors may lead to a wrong conclusions or some misinterpretation. So it the word "return". This word is useful only in a single-threaded execution (i.e. in the thread which actually created an object). There are neither "rewrite" no "return" in formal memory model (except in example's explanations and final field semantics). There are only reads and writes (observable or not). Read of holder variable may see any write (let's assume that this is not prevented by causality requirement, it is not prevented in my example). Read of it's field may see at least two writes. These writes are an initial write of zero and a write of 42 in the constructor. And this is because there is no happens-before relationship which prevents first write (of 0) been observed. Period. These reads may see any writes. These reads even may see values which will be written an hour later (unless there are no casuality or happens-before breaks). And it may choose any observable write to "read" it's value (so you may observe "flipping" of value to 42 and back to zero, which was not allowed until JLS 3).

And in general Java Memory Model does not describes "how the program may behave". It describes only "how program must not behave" (happens-before relationship really specifies only "writes cannot be observed"). And as far as I remember, instance creation expression (new keyword) have no special meaning in JLS except final field semantics.
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, Maxim.

Few days back, I was trying to create ( and I understand it is difficult to create such cases as we can't predict the reordering ) the case ( with delays and such things, making construction a lengthy process with assignment to many non final variables ) of how I could have one thread construct an object and another thread have access to that object even before the construction was complete. The only thing that came to my mind was DCL way of coding. And I didn't want to code in that same way. So while I intended to actually code something like what you have shown in your code, I actually wrote far more complicated code that didn't quite fit the requirement. The example you have shown is perhaps the easiest way to have one thread construct an object and the chances of having another thread access it even before the construction is complete.

And I love the way you've explained the reads and writes in your second post. Particularly this part -->

And in general Java Memory Model does not describes "how the program may behave". It describes only "how program must not behave" (happens-before relationship really specifies only "writes cannot be observed").





 
Consider Paul's rocket mass heater.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!