• 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

Head First Design patterns: Singleton

 
Ranch Hand
Posts: 87
  • Number of slices to send:
    Optional 'thank-you' note:


Why is the need for volatile for uniqueInstance variable? Two threads(or more) entered first null check if block, and only one thread goes through synchronized block.  By the time, the first thread left the synchronized block, the write of the uniqueInstance variable is published(JMM rules) for second thread(or all threads) to see. Isn't it?
 
Marshal
Posts: 28262
95
  • Number of slices to send:
    Optional 'thank-you' note:
If I remember my ancient history correctly, the "double-checked locking" code there used to be subject to an obscure memory problem which supposedly could cause the synchronization to fail. Perhaps the use of volatile was meant to deal with that problem? That's definitely way above my skill level. Anyway that obscure memory problem was fixed approximately when Java 5 was released, again if I remember my ancient history right.
 
Saloon Keeper
Posts: 15620
366
  • 1
  • Number of slices to send:
    Optional 'thank-you' note:
The reason the volatile keyword is necessary may indeed be obscure, but the memory issue fix in Java 5 does NOT make its use in that example code optional.

Java 5 introduced a new memory model that, among other things, ensures that the way volatile is used in that example code will indeed work. Before Java 5, all bets were off.

So why is volatile still necessary for the double-checked locking pattern, even today?

The JVM is free to reorder instructions as it sees fit, as long as it doesn't affect the final result as observed by the thread executing those instructions. Importantly, that guarantee does not take other threads into account!

Let's say thread 1 has entered the synchronized block and has just finished assigning a reference to uniqueInstance. Thread 2 is currently executing the first if-statement. Thread 2 sees that uniqueInstance is assigned, and so returns the reference immediately.

The calling code that thread 2 returns to might call methods on the returned singleton object. Without volatile, those calls might crash or lead to unexpected results because the singleton object has not been properly initialized.

How is that possible? Thread 1 initialized the singleton object and then assigned it to the uniqueInstance field, right? Well no, not necessarily.

You see, thread 1 might have assigned a memory address to the field BEFORE it went on to initialize the new object. It's free to reorder instructions, after all. To thread 1, it doesn't matter whether it assigns the field first, or whether it initializes the object first.

The volatile keyword really only does one thing: whenever you access a volatile field, all instructions that happened-before accesses to that same field in a different thread, unscramble!

The term happens-before has a very exact and technical definition. For the messy details, you should refer to the JLS and the JVMS. In this particular example, it means the following:

From the viewpoint of thread 1, initialization of the object happens-before the assignment of the static field, ALWAYS. However, this is just a point of view, it may not reflect reality.

Without volatile, thread 2 may not agree. When you make the field volatile however, thread 2 will now agree with thread 1 that the initialization of the object happens-before the assignment of the field.
 
Marshal
Posts: 79422
377
  • Number of slices to send:
    Optional 'thank-you' note:
Apart from the fact that some people think Singleton is an anti‑pattern:-
There are at least two better ways to write a Singleton. You should be able to find both in Effective Java by Joshua Bloch.I think I prefer the solution with the enum.
 
Stephan van Hulst
Saloon Keeper
Posts: 15620
366
  • 2
  • Number of slices to send:
    Optional 'thank-you' note:
There simply is no raison d'ĂȘtre for the Singleton pattern.

If you don't want more than a single instance of a value type, then use an enum, like Campbell showed.

If you don't want more than a single instance of a service type, then just don't create more than one instance of it. It's that simple. Pass the instance around as a constructor/method argument.

If you want to access global state, then stop programming and slap yourself.
 
Campbell Ritchie
Marshal
Posts: 79422
377
  • Number of slices to send:
    Optional 'thank-you' note:

Stephan van Hulst wrote:There simply is no raison d'ĂȘtre for the Singleton pattern. . . .

You are obviously one of those people who regard it as an anti‑pattern.

If you want to access global state, then stop programming and slap yourself.

No, let us all slap you in turn
 
Paul Clapham
Marshal
Posts: 28262
95
  • Number of slices to send:
    Optional 'thank-you' note:

Stephan van Hulst wrote:The reason the volatile keyword is necessary may indeed be obscure, but the memory issue fix in Java 5 does NOT make its use in that example code optional.



Thank you Stephan.

It's certainly true that the code in the OP is long since obsolete, but it looks like it still serves as a useful example for the volatile keyword.
 
Bhaskar Bantupalli
Ranch Hand
Posts: 87
  • Number of slices to send:
    Optional 'thank-you' note:

From the viewpoint of thread 1, initialization of the object happens-before the assignment of the static field, ALWAYS. However, this is just a point of view, it may not reflect reality.


Can you explain more about why your second sentence is opposite of what the first sentence is? Also, I couldn't find the source where I read a similar statement to your first sentence(in quotes)

Without volatile, thread 2 may not agree. When you make the field volatile however, thread 2 will now agree with thread 1 that the initialization of the object happens-before the assignment of the field.


Aren't `synchronized` semantics stronger than volatile? By stronger, I mean it is either fully published or it isn't(atomic)

Is it not properly published because if the second thread is at first if(instead of at begin of synchronized block waiting for lock acquire)?
 
Bartender
Posts: 2436
13
  • Number of slices to send:
    Optional 'thank-you' note:
I found this article mentioning that the volatile keyword is to cache incoherence issue.
https://www.baeldung.com/java-singleton-double-checked-locking

I heard declaring a variable as volatile means storing it in the main memory instead of local cache of each CPU core.
Reading from the main memory can get the most updated value. Reading from the cache may not get the updated value.

 
Stephan van Hulst
Saloon Keeper
Posts: 15620
366
  • 1
  • Number of slices to send:
    Optional 'thank-you' note:

Bhaskar Bantupalli wrote:Can you explain more about why your second sentence is opposite of what the first sentence is?


To the code executed by thread 1, it really doesn't matter what happens first. Maybe the reference is assigned to the field first. Maybe the object is initialized first. The end result is the same: A reference to the initialized object is assigned to the field. Even if it doesn't matter which instruction is executed by the JVM in reality, from an abstract conceptual point of view, we may assume that instructions are executed in the same order they appear in the code. This conceptual point of view is encoded in the technical term happens-before, as defined by the Java Language Specification.

So even IF the JVM executes the assignment before it executes the initialization, we say that the initialization happens-before the assignment. However, this happens-before relationship between these two instructions is determined separately for each thread. If one instruction happens-before another instruction for thread 1, that doesn't mean that that instruction also happens-before the other instruction for thread 2. To ensure that two threads agree on the happens-before relationship, you need to synchronize them carefully. Synchronization is done using concurrency utilities and the keywords, synchronized, volatile and final.

Also, I couldn't find the source where I read a similar statement to your first sentence


I paraphrased from the JLS. The actual text is very technical. Here is the source: https://docs.oracle.com/javase/specs/jls/se17/html/jls-17.html#jls-17.4.5

These two sentences in particular seem relevant though:

Java Language Specification wrote:It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.

More specifically, if two actions share a happens-before relationship, they do not necessarily have to appear to have happened in that order to any code with which they do not share a happens-before relationship. Writes in one thread that are in a data race with reads in another thread may, for example, appear to occur out of order to those reads.



Aren't `synchronized` semantics stronger than volatile?


Sure. But what use is a synchronized block if a thread never reaches it? That is, when a thread sees that uniqueInstance is not null, and then decides to immediately return it without going into the synchronized block.

Is it not properly published because if the second thread is at first if(instead of at begin of synchronized block waiting for lock acquire)?


Correct. Even though thread 1 is inside the synchronized block, any operations inside that block may still seem out-of-order to any other thread that is out-of-sync with thread 1. Remember that synchronization is a two way street: One thread needs to publish its local state of affairs, but other threads also need to update their local state of affairs. This update happens when a thread locks on a shared monitor using the synchronized keyword, or it happens when a thread accesses a shared volatile field.

Note that synchronized and volatile work in EXACTLY the same way with regards to this "memory barrier" function. The only difference between the two keywords is that synchronized in addition to its memory barrier function, also provides "mutual exclusion", the function that two threads can't enter the same critical section of code at the same time.
 
Stephan van Hulst
Saloon Keeper
Posts: 15620
366
  • Number of slices to send:
    Optional 'thank-you' note:

Himai Minh wrote:I heard declaring a variable as volatile means storing it in the main memory instead of local cache of each CPU core.


I've often heard it phrased this way as well. This explanation is, however, not only incomplete, but it might even be incorrect (although that is unlikely).

Whether a volatile field is never cached locally doesn't matter. The true purpose of declaring a field volatile is as follows:

Whenever you write to a volatile field, any locally cached state that has changed since the previous update is written to main memory, not just the volatile field itself.

Whenever you read from a volatile field, the locally cached state is updated with any changes that have been written to main memory since the previous update.
 
Himai Minh
Bartender
Posts: 2436
13
  • Number of slices to send:
    Optional 'thank-you' note:
Hi I think volatile is for long,float and double field's value assignments. With volatile, the happens-before relationship is guaranteed by the compiler.
For example,
volatile long x ;
volatile long y;

x++;
y++;
This can guarantee the compiler won't do y++ before x++.
So, x > y is always true in multiple threads executions.
Example case:
x and y are initialized to 0.
Thread 1: increase x  to 1
Thread 2:  x>= y is true since x =1 , y=0
Thread 1 increase y to 1
Thread 2 : x > = y is true since x and y are 1.


However,
long x;
long y;
x++;
y++;
The compiler may do y++ before x++ since it does not care about the order of execution of these two independent lines of code.
So, you may end up y > x situation in multiple threads executions. You will be surprised to see y> x
Surprised case:
x and y are initialized to 0
Thread 1 : increase y = 1
Thread 2 : x>=y is false ( you will be surprised as y is increased first before x. The compiler unexpectedly swaps the order of executions of x++ and y++)
Thread 1: increase x = 1

 
Campbell Ritchie
Marshal
Posts: 79422
377
  • Number of slices to send:
    Optional 'thank-you' note:
I thought you can make any variable of any type volatile.
 
Himai Minh
Bartender
Posts: 2436
13
  • Number of slices to send:
    Optional 'thank-you' note:
Yes. You can make any variables to volatile.
However, if the 64  bit variable is a float, long, double or big decimal, making it volatile is necessary if you want to guarantee the assignment is atomic.
https://stackoverflow.com/questions/25070808/how-volatile-keyword-influences-atomicity-when-defining-a-long-or-double-variabl
 
Campbell Ritchie
Marshal
Posts: 79422
377
  • Number of slices to send:
    Optional 'thank-you' note:
There is an example in Core Java (Cai Horstmann and, in earlier editions, Gary Cornell) called BadBank or similar where you repeatedly transfer longs back and forth between to “accounts” and because long arithmetic can be implemented as two lots of 32 bits.
 
Campbell Ritchie
Marshal
Posts: 79422
377
  • Number of slices to send:
    Optional 'thank-you' note:

Earlier today, I wrote:. . . because long arithmetic can be implemented as two lots of 32 bits.

I should have written

. . . . the balances gradually decline.

. . . after it.
 
Master Rancher
Posts: 4913
74
  • Number of slices to send:
    Optional 'thank-you' note:

Campbell Ritchie wrote:I think I prefer the solution with the enum.


Ummm... the way you wrote it, Campbell, they both use enum.  However, the first one won't compile, because it was apparently intended to be a class, not an enum.
 
reply
    Bookmark Topic Watch Topic
  • New Topic
vceplus-200-125    | boson-200-125    | training-cissp    | actualtests-cissp    | techexams-cissp    | gratisexams-300-075    | pearsonitcertification-210-260    | examsboost-210-260    | examsforall-210-260    | dumps4free-210-260    | reddit-210-260    | cisexams-352-001    | itexamfox-352-001    | passguaranteed-352-001    | passeasily-352-001    | freeccnastudyguide-200-120    | gocertify-200-120    | passcerty-200-120    | certifyguide-70-980    | dumpscollection-70-980    | examcollection-70-534    | cbtnuggets-210-065    | examfiles-400-051    | passitdump-400-051    | pearsonitcertification-70-462    | anderseide-70-347    | thomas-70-533    | research-1V0-605    | topix-102-400    | certdepot-EX200    | pearsonit-640-916    | itproguru-70-533    | reddit-100-105    | channel9-70-346    | anderseide-70-346    | theiia-IIA-CIA-PART3    | certificationHP-hp0-s41    | pearsonitcertification-640-916    | anderMicrosoft-70-534    | cathMicrosoft-70-462    | examcollection-cca-500    | techexams-gcih    | mslearn-70-346    | measureup-70-486    | pass4sure-hp0-s41    | iiba-640-916    | itsecurity-sscp    | cbtnuggets-300-320    | blogged-70-486    | pass4sure-IIA-CIA-PART1    | cbtnuggets-100-101    | developerhandbook-70-486    | lpicisco-101    | mylearn-1V0-605    | tomsitpro-cism    | gnosis-101    | channel9Mic-70-534    | ipass-IIA-CIA-PART1    | forcerts-70-417    | tests-sy0-401    | ipasstheciaexam-IIA-CIA-PART3    | mostcisco-300-135    | buildazure-70-533    | cloudera-cca-500    | pdf4cert-2v0-621    | f5cisco-101    | gocertify-1z0-062    | quora-640-916    | micrcosoft-70-480    | brain2pass-70-417    | examcompass-sy0-401    | global-EX200    | iassc-ICGB    | vceplus-300-115    | quizlet-810-403    | cbtnuggets-70-697    | educationOracle-1Z0-434    | channel9-70-534    | officialcerts-400-051    | examsboost-IIA-CIA-PART1    | networktut-300-135    | teststarter-300-206    | pluralsight-70-486    | coding-70-486    | freeccna-100-101    | digitaltut-300-101    | iiba-CBAP    | virtuallymikebrown-640-916    | isaca-cism    | whizlabs-pmp    | techexams-70-980    | ciscopress-300-115    | techtarget-cism    | pearsonitcertification-300-070    | testking-2v0-621    | isacaNew-cism    | simplilearn-pmi-rmp    | simplilearn-pmp    | educationOracle-1z0-809    | education-1z0-809    | teachertube-1Z0-434    | villanovau-CBAP    | quora-300-206    | certifyguide-300-208    | cbtnuggets-100-105    | flydumps-70-417    | gratisexams-1V0-605    | ituonline-1z0-062    | techexams-cas-002    | simplilearn-70-534    | pluralsight-70-697    | theiia-IIA-CIA-PART1    | itexamtips-400-051    | pearsonitcertification-EX200    | pluralsight-70-480    | learn-hp0-s42    | giac-gpen    | mindhub-102-400    | coursesmsu-CBAP    | examsforall-2v0-621    | developerhandbook-70-487    | root-EX200    | coderanch-1z0-809    | getfreedumps-1z0-062    | comptia-cas-002    | quora-1z0-809    | boson-300-135    | killtest-2v0-621    | learncia-IIA-CIA-PART3    | computer-gcih    | universitycloudera-cca-500    | itexamrun-70-410    | certificationHPv2-hp0-s41    | certskills-100-105    | skipitnow-70-417    | gocertify-sy0-401    | prep4sure-70-417    | simplilearn-cisa    |
http://www.pmsas.pr.gov.br/wp-content/    | http://www.pmsas.pr.gov.br/wp-content/    |