Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Double-checked locking
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== Motivation and original pattern == Consider, for example, this code segment in the [[Java (programming language)|Java programming language]]:<ref name="bdec" /> <syntaxhighlight lang="java"> // Single-threaded version class Foo { private static Helper helper; public Helper getHelper() { if (helper == null) { helper = new Helper(); } return helper; } // other functions and members... } </syntaxhighlight> The problem is that this does not work when using multiple threads. A [[lock (computer science)|lock]] must be obtained in case two threads call <code>getHelper()</code> simultaneously. Otherwise, either they may both try to create the object at the same time, or one may wind up getting a reference to an incompletely initialized object. Synchronizing with a lock can fix this, as is shown in the following example: <syntaxhighlight lang="java"> // Correct but possibly expensive multithreaded version class Foo { private Helper helper; public synchronized Helper getHelper() { if (helper == null) { helper = new Helper(); } return helper; } // other functions and members... } </syntaxhighlight> This is correct and will most likely have sufficient performance. However, the first call to <code>getHelper()</code> will create the object and only the few threads trying to access it during that time need to be synchronized; after that all calls just get a reference to the member variable. Since synchronizing a method could in some extreme cases decrease performance by a factor of 100 or higher,<ref name=Boehm2005>{{cite journal|last=Boehm|first=Hans-J|title=Threads cannot be implemented as a library|journal=ACM SIGPLAN Notices|date=Jun 2005|volume=40|issue=6|pages=261β268|doi=10.1145/1064978.1065042|url=http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf|access-date=2014-08-12|archive-date=2017-05-30|archive-url=https://web.archive.org/web/20170530160703/http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf|url-status=dead}}</ref> the overhead of acquiring and releasing a lock every time this method is called seems unnecessary: once the initialization has been completed, acquiring and releasing the locks would appear unnecessary. Many programmers, including the authors of the double-checked locking design pattern, have attempted to optimize this situation in the following manner: # Check that the variable is initialized (without obtaining the lock). If it is initialized, return it immediately. # Obtain the lock. # Double-check whether the variable has already been initialized: if another thread acquired the lock first, it may have already done the initialization. If so, return the initialized variable. # Otherwise, initialize and return the variable. <syntaxhighlight lang="java"> // Broken multithreaded version // original "Double-Checked Locking" idiom class Foo { private Helper helper; public Helper getHelper() { if (helper == null) { synchronized (this) { if (helper == null) { helper = new Helper(); } } } return helper; } // other functions and members... } </syntaxhighlight> Intuitively, this algorithm is an efficient solution to the problem. But if the pattern is not written carefully, it will have a [[data race]]. For example, consider the following sequence of events: # Thread ''A'' notices that the value is not initialized, so it obtains the lock and begins to initialize the value. # Due to the semantics of some programming languages, the code generated by the compiler is allowed to update the shared variable to point to a ''partially constructed'' object before ''A'' has finished performing the initialization. For example, in Java if a call to a constructor has been inlined then the shared variable may immediately be updated once the storage has been allocated but before the inlined constructor initializes the object.<ref name=IBM>{{cite web|last=Haggar|first=Peter|title=Double-checked locking and the Singleton pattern|url=http://www.ibm.com/developerworks/java/library/j-dcl/index.html|publisher=IBM|date=1 May 2002|archive-url=https://web.archive.org/web/20171027162134/https://www.ibm.com/developerworks/java/library/j-dcl/index.html |archive-date=2017-10-27|access-date=2022-05-19|url-status=dead}}</ref> # Thread ''B'' notices that the shared variable has been initialized (or so it appears), and returns its value. Because thread ''B'' believes the value is already initialized, it does not acquire the lock. If ''B'' uses the object before all of the initialization done by ''A'' is seen by ''B'' (either because ''A'' has not finished initializing it or because some of the initialized values in the object have not yet percolated to the memory ''B'' uses ([[cache coherence]])), the program will likely crash. Most runtimes have [[memory barrier]]s or other methods for managing memory visibility across execution units. Without a detailed understanding of the language's behavior in this area, the algorithm is difficult to implement correctly. One of the dangers of using double-checked locking is that even a naive implementation will appear to work most of the time: it is not easy to distinguish between a correct implementation of the technique and one that has subtle problems. Depending on the [[compiler]], the interleaving of threads by the [[Scheduling (computing)|scheduler]] and the nature of other [[concurrency (computer science)|concurrent system activity]], failures resulting from an incorrect implementation of double-checked locking may only occur intermittently. Reproducing the failures can be difficult.
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)