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!
== Usage in Java == As of [[Java Platform, Standard Edition|J2SE 5.0]], the [[Volatile variable|volatile]] keyword is defined to create a memory barrier. This allows a solution that ensures that multiple threads handle the singleton instance correctly. This new idiom is described in [http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html] and [http://www.oracle.com/technetwork/articles/javase/bloch-effective-08-qa-140880.html]. <syntaxhighlight lang="java"> // Works with acquire/release semantics for volatile in Java 1.5 and later // Broken under Java 1.4 and earlier semantics for volatile class Foo { private volatile Helper helper; public Helper getHelper() { Helper localRef = helper; if (localRef == null) { synchronized (this) { localRef = helper; if (localRef == null) { helper = localRef = new Helper(); } } } return localRef; } // other functions and members... } </syntaxhighlight> Note the [[local variable]] "{{mono|localRef}}", which seems unnecessary. The effect of this is that in cases where {{mono|helper}} is already initialized (i.e., most of the time), the volatile field is only accessed once (due to "{{mono|return localRef;}}" instead of "{{mono|return helper;}}"), which can improve the method's overall performance by as much as 40 percent.<ref>{{cite book |last1=Bloch |first1=Joshua |title=Effective Java |date=2018 |publisher=Addison-Wesley |isbn=978-0-13-468599-1 |page=335 |edition=Third |quote=On my machine, the method above is about 1.4 times as fast as the obvious version without a local variable.}}</ref> Java 9 introduced the {{Javadoc:SE|java/lang/invoke|VarHandle}} class, which allows use of relaxed atomics to access fields, giving somewhat faster reads on machines with weak memory models, at the cost of more difficult mechanics and loss of [[sequential consistency]] (field accesses no longer participate in the synchronization order, the global order of accesses to volatile fields).<ref>{{Cite web|url=https://docs.oracle.com/javase/specs/jls/se10/html/jls-17.html#jls-17.4.4|title=Chapter 17. Threads and Locks|website=docs.oracle.com|access-date=2018-07-28}}</ref> <syntaxhighlight lang="java"> // Works with acquire/release semantics for VarHandles introduced in Java 9 class Foo { private volatile Helper helper; public Helper getHelper() { Helper localRef = getHelperAcquire(); if (localRef == null) { synchronized (this) { localRef = getHelperAcquire(); if (localRef == null) { localRef = new Helper(); setHelperRelease(localRef); } } } return localRef; } private static final VarHandle HELPER; private Helper getHelperAcquire() { return (Helper) HELPER.getAcquire(this); } private void setHelperRelease(Helper value) { HELPER.setRelease(this, value); } static { try { MethodHandles.Lookup lookup = MethodHandles.lookup(); HELPER = lookup.findVarHandle(Foo.class, "helper", Helper.class); } catch (ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); } } // other functions and members... } </syntaxhighlight> If the helper object is static (one per class loader), an alternative is the [[initialization-on-demand holder idiom]]<ref>Brian Goetz et al. Java Concurrency in Practice, 2006 pp348</ref> (See Listing 16.6<ref name=JCP>{{cite web|last1=Goetz|first1=Brian|title=Java Concurrency in Practice β listings on website|url=http://jcip.net.s3-website-us-east-1.amazonaws.com/listings.html|access-date=21 October 2014|display-authors=etal}}</ref> from the previously cited text.) <syntaxhighlight lang="java"> // Correct lazy initialization in Java class Foo { private static class HelperHolder { public static final Helper helper = new Helper(); } public static Helper getHelper() { return HelperHolder.helper; } } </syntaxhighlight> This relies on the fact that nested classes are not loaded until they are referenced. Semantics of {{mono|final}} field in Java 5 can be employed to safely publish the helper object without using {{mono|volatile}}:<ref>[https://mailman.cs.umd.edu/mailman/private/javamemorymodel-discussion/2010-July/000422.html] Javamemorymodel-discussion mailing list{{Stale|text=Page not found β consider updating the link}}</ref> <syntaxhighlight lang="java"> public class FinalWrapper<T> { public final T value; public FinalWrapper(T value) { this.value = value; } } public class Foo { private FinalWrapper<Helper> helperWrapper; public Helper getHelper() { FinalWrapper<Helper> tempWrapper = helperWrapper; if (tempWrapper == null) { synchronized (this) { if (helperWrapper == null) { helperWrapper = new FinalWrapper<Helper>(new Helper()); } tempWrapper = helperWrapper; } } return tempWrapper.value; } } </syntaxhighlight> The local variable {{mono|tempWrapper}} is required for correctness: simply using {{mono|helperWrapper}} for both null checks and the return statement could fail due to read reordering allowed under the Java Memory Model.<ref>[http://jeremymanson.blogspot.ru/2008/12/benign-data-races-in-java.html] {{cite web |last1=Manson |first1=Jeremy |date=2008-12-14 |title=Date-Race-Ful Lazy Initialization for Performance β Java Concurrency (&c) |url=http://jeremymanson.blogspot.ru/2008/12/benign-data-races-in-java.html |access-date=3 December 2016}}</ref> Performance of this implementation is not necessarily better than the {{mono|volatile}} implementation.
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)