...
Code Block |
---|
|
class Foo {
private final ThreadLocal<Foo> perThreadInstance = new ThreadLocal<Foo>();
private Helper helper = null;
public Helper getHelper() {
if (perThreadInstance.get() == null) {
createHelper();
}
return helper;
}
private final synchronized void createHelper() {
if (helper == null) {
helper = new Helper();
}
// Any non-null value can be used as an argument to set()
perThreadInstance.set(this);
}
}
|
Compliant Solution (Immutable)
In this compliant solution the Helper
class is immutable and is consequently guaranteed to be fully constructed before becoming visible. In this case, there are no further requirements to ensure that the double-checked locking idiom does not result in the publication of an uninitialized or partially initialized field.
Code Block |
---|
|
public final class Helper {
private final int n;
public Helper(int n) {
this.n = n;
}
// Other fields and methods, all fields are final
}
final class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized (this) {
if (helper == null) {
helper = new Helper(); // If the helper is null, create a new instance
}
}
}
return helper; // If helper is non-null, return its instance
}
}
|
Exceptions
Wiki Markup |
---|
*CON22-EX1:* The noncompliant form of the double-checked locking idiom can be used for for 32-bit primitive values (for example, {{int}} or {{float}}) \[[Pugh 04|AA. Java References#Pugh 04]\]. Note that it does not work for {{long}} or {{double}} because unsynchronized reads/writes of 64-bit primitives are not guaranteed to be atomic (see [CON25-J. Ensure atomicity when reading and writing 64-bit values].) |
...