From reading the JLS after a frustrating debugging session I find that lambdas will capture the value of effectively-final local variables, but if you refer to an instance variable it captures a reference to the variable, which has serious implications for multi-threaded code.
For example, the following is an MCVE distilled from a much larger program:
public class LambdaCapture
{
public static void main(String[] args) throws Exception
{
Launcher i1 = new Launcher();
i1.launchAsynchTask();
}
public static class Launcher
{
private int value = 10;
public void launchAsynchTask() throws Exception
{
System.out.printf("In launchAsynchTask value is %s\n",value);
Thread t = new Thread(()->doSomething(value));
t.start();
value = -1;
t.join();
}
public void doSomething(int value)
{
System.out.printf("In asynch task, value is %s\n",value);
}
}
}
I found the output surprising. It is
In launchAsynchTask value is 10
In asynch task, value is -1
since I initially (prior to JLS research) and intuitively expected the lambda to capture the value of the variable value instead of a reference to it.
If I have to guarantee that the current value is captured instead of a reference the obvious solution is to create a local final temporary:
final int capture = this.value;
Thread t = new Thread(()->doSomething(capture));
My question: Is this the accepted idiomatic way to force value capture, or is there some other more natural way to do it?
I ... intuitively expected the lambda to capture the value of the variable value instead of a reference to it.
That (capturing the value) is what happens with local variables.
With fields, what is actually happening is that you are capturing a reference to the instance of the object that the field belongs to. In your case, it is a reference to the Launcher.this object. (The same thing happens when you declare an inner class.)
My question: Is this the accepted idiomatic way to force value capture, or is there some other more natural way to do it?
I can't think of a better way.
Because you're using shorthand syntax, it's not as obvious what is going on.
When you write value to access the field, it implicitly means this.value.
The lambda expression is capturing the absolutely final "local variable" this that is implicit to all non-static methods.
The lambda expression
()->doSomething(value)
is logically equivalent to
new Lambda$1(this)
where Lambda$1 is declared like this (using arbitrary names):
private static final class Lambda$1 implements Runnable {
private final Launcher ref;
Lambda$1(Launcher ref) {
this.ref = ref;
}
#Override
public void run() {
this.ref.doSomething(this.ref.value);
}
}
As you can see, the lambda expression ()->doSomething(value) is not actually capturing value. The unqualified field access is obscuring what is actually happening.
FYI: Hiding field value behind parameter value in the doSomething() method is a bad idea. The name conflict makes the code very vulnerable to misinterpretation by programmers, and good IDEs will warn you about it (unless you disabled that warning).
Hopefully that just happened by mistake here when creating an MCVE, and you wouldn't do that in real code. :-)
What I normally like to do is to minimize code parts that access fields directly, so you could wrap the part starting the thread in a function like this:
public void launchAsynchTask() throws Exception
{
System.out.printf("In launchAsynchTask value is %s\n", this.value);
Thread t = launchAsynchTaskWithValue(this.value);
this.value = -1;
t.join();
}
public Thread launchAsynchTaskWithValue(int launchValue) throws Exception
{
Thread t = new Thread(()->doSomething(launchValue));
t.start();
return t;
}
Related
a can only be final here. Why? How can I reassign a in onClick() method without keeping it as private member?
private void f(Button b, final int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
}
});
}
How can I return the 5 * a when it clicked? I mean,
private void f(Button b, final int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
return b; // but return type is void
}
});
}
As noted in comments, some of this becomes irrelevant in Java 8, where final can be implicit. Only an effectively final variable can be used in an anonymous inner class or lambda expression though.
It's basically due to the way Java manages closures.
When you create an instance of an anonymous inner class, any variables which are used within that class have their values copied in via the autogenerated constructor. This avoids the compiler having to autogenerate various extra types to hold the logical state of the "local variables", as for example the C# compiler does... (When C# captures a variable in an anonymous function, it really captures the variable - the closure can update the variable in a way which is seen by the main body of the method, and vice versa.)
As the value has been copied into the instance of the anonymous inner class, it would look odd if the variable could be modified by the rest of the method - you could have code which appeared to be working with an out-of-date variable (because that's effectively what would be happening... you'd be working with a copy taken at a different time). Likewise if you could make changes within the anonymous inner class, developers might expect those changes to be visible within the body of the enclosing method.
Making the variable final removes all these possibilities - as the value can't be changed at all, you don't need to worry about whether such changes will be visible. The only ways to allow the method and the anonymous inner class see each other's changes is to use a mutable type of some description. This could be the enclosing class itself, an array, a mutable wrapper type... anything like that. Basically it's a bit like communicating between one method and another: changes made to the parameters of one method aren't seen by its caller, but changes made to the objects referred to by the parameters are seen.
If you're interested in a more detailed comparison between Java and C# closures, I have an article which goes into it further. I wanted to focus on the Java side in this answer :)
There is a trick that allows anonymous class to update data in the outer scope.
private void f(Button b, final int a) {
final int[] res = new int[1];
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
res[0] = a * 5;
}
});
// But at this point handler is most likely not executed yet!
// How should we now res[0] is ready?
}
However, this trick is not very good due to the synchronization issues. If handler is invoked later, you need to 1) synchronize access to res if handler was invoked from the different thread 2) need to have some sort of flag or indication that res was updated
This trick works OK, though, if anonymous class is invoked in the same thread immediately. Like:
// ...
final int[] res = new int[1];
Runnable r = new Runnable() { public void run() { res[0] = 123; } };
r.run();
System.out.println(res[0]);
// ...
An anonymous class is an inner class and the strict rule applies to inner classes (JLS 8.1.3):
Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned before the body of the inner class.
I haven't found a reason or an explanation on the jls or jvms yet, but we do know, that the compiler creates a separate class file for each inner class and it has to make sure, that the methods declared on this class file (on byte code level) at least have access to the values of local variables.
(Jon has the complete answer - I keep this one undeleted because one might interested in the JLS rule)
You can create a class level variable to get returned value. I mean
class A {
int k = 0;
private void f(Button b, int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
k = a * 5;
}
});
}
now you can get value of K and use it where you want.
Answer of your why is :
A local inner class instance is tied to Main class and can access the final local variables of its containing method. When the instance uses a final local of its containing method, the variable retains the value it held at the time of the instance's creation, even if the variable has gone out of scope (this is effectively Java's crude, limited version of closures).
Because a local inner class is neither the member of a class or package, it is not declared with an access level. (Be clear, however, that its own members have access levels like in a normal class.)
To understand the rationale for this restriction, consider the following program:
public class Program {
interface Interface {
public void printInteger();
}
static Interface interfaceInstance = null;
static void initialize(int val) {
class Impl implements Interface {
#Override
public void printInteger() {
System.out.println(val);
}
}
interfaceInstance = new Impl();
}
public static void main(String[] args) {
initialize(12345);
interfaceInstance.printInteger();
}
}
The interfaceInstance remains in memory after the initialize method returns, but the parameter val does not. The JVM can’t access a local variable outside its scope, so Java makes the subsequent call to printInteger work by copying the value of val to an implicit field of the same name within interfaceInstance. The interfaceInstance is said to have captured the value of the local parameter. If the parameter weren’t final (or effectively final) its value could change, becoming out of sync with the captured value, potentially causing unintuitive behavior.
Well, in Java, a variable can be final not just as a parameter, but as a class-level field, like
public class Test
{
public final int a = 3;
or as a local variable, like
public static void main(String[] args)
{
final int a = 3;
If you want to access and modify a variable from an anonymous class, you might want to make the variable a class-level variable in the enclosing class.
public class Test
{
public int a;
public void doSomething()
{
Runnable runnable =
new Runnable()
{
public void run()
{
System.out.println(a);
a = a+1;
}
};
}
}
You can't have a variable as final and give it a new value. final means just that: the value is unchangeable and final.
And since it's final, Java can safely copy it to local anonymous classes. You're not getting some reference to the int (especially since you can't have references to primitives like int in Java, just references to Objects).
It just copies over the value of a into an implicit int called a in your anonymous class.
The reason why the access has been restricted only to the local final variables is that if all the local variables would be made accessible then they would first required to be copied to a separate section where inner classes can have access to them and maintaining multiple copies of mutable local variables may lead to inconsistent data. Whereas final variables are immutable and hence any number of copies to them will not have any impact on the consistency of data.
When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. For scalar values, once it has been assigned, the value of the final variable cannot change. For object values, the reference cannot change. This allows the Java compiler to "capture" the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed, the original variable is gone but the inner class's private copy persists in the class's own memory.
(http://en.wikipedia.org/wiki/Final_%28Java%29)
Methods within an anonomyous inner class may be invoked well after the thread that spawned it has terminated. In your example, the inner class will be invoked on the event dispatch thread and not in the same thread as that which created it. Hence, the scope of the variables will be different. So to protect such variable assignment scope issues you must declare them final.
private void f(Button b, final int a[]) {
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
a[0] = a[0] * 5;
}
});
}
As Jon has the implementation details answer an other possible answer would be that the JVM doesn't want to handle write in record that have ended his activation.
Consider the use case where your lambdas instead of being apply, is stored in some place and run later.
I remember that in Smalltalk you would get an illegal store raised when you do such modification.
Try this code,
Create Array List and put value inside that and return it :
private ArrayList f(Button b, final int a)
{
final ArrayList al = new ArrayList();
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
al.add(b);
}
});
return al;
}
Java anonymous class is very similar to Javascript closure, but Java implement that in different way. (check Andersen's answer)
So in order not to confuse the Java Developer with the strange behavior that might occur for those coming from Javascript background. I guess that's why they force us to use final, this is not the JVM limitation.
Let's look at the Javascript example below:
var add = (function () {
var counter = 0;
var func = function () {
console.log("counter now = " + counter);
counter += 1;
};
counter = 100; // line 1, this one need to be final in Java
return func;
})();
add(); // this will print out 100 in Javascript but 0 in Java
In Javascript, the counter value will be 100, because there is only one counter variable from the beginning to end.
But in Java, if there is no final, it will print out 0, because while the inner object is being created, the 0 value is copied to the inner class object's hidden properties. (there are two integer variable here, one in the local method, another one in inner class hidden properties)
So any changes after the inner object creation (like line 1), it will not affect the inner object. So it will make confusion between two different outcome and behaviour (between Java and Javascript).
I believe that's why, Java decide to force it to be final, so the data is 'consistent' from the beginning to end.
Java final variable inside an inner class[About]
inner class can use only
reference from outer class
final local variables from out of scope which are a reference type (e.g. Object...)
value(primitive) (e.g. int...) type can be wrapped by a final reference type. IntelliJ IDEA can help you covert it to one element array
When a non static nested (inner class) is generated by compiler - a new class - <OuterClass>$<InnerClass>.class is created and bounded parameters are passed into constructor[Local variable on stack] It is similar to closure[Swift about]
final variable is a variable which can not be reassign. final reference variable still can be changed by modifying a state
If it was be possible it would be weird because as a programmer you could make like this
//Not possible
private void foo() {
MyClass myClass = new MyClass(); //Case 1: myClass address is 1
int a = 5; //Case 2: a = 5
//just as an example
new Button().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
/*
myClass.something(); //<- what is the address - 1 or 2?
int b = a; //<- what is the value - 5 or 10 ?
//illusion that next changes are visible for Outer class
myClass = new MyClass();
a = 15;
*/
}
});
myClass = new MyClass(); //Case 1: myClass address is 2
int a = 10; //Case 2: a = 10
}
Maybe this trick gives u an idea
Boolean var= new anonymousClass(){
private String myVar; //String for example
#Overriden public Boolean method(int i){
//use myVar and i
}
public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);
I would like to know if this piece of code is correct or not. Will this not lead to issues as I am submitting the runnable object to the executor service while constructing the object itself?
public class A implements Runnable {
public A() {
Executors.newSingleThreadExecutor().execute(this);
// some other initializations
}
}
Will this lead to any issues as we are trying to submit the object to the executor even before creating it completely? If the run() method is called even before all the initializing is done (if at all it's possible), will the variables still be null which were not yet initialized?
Please do not ask me to come up with the complete code, as I have been asking this as a general question which requires clarification.
Yes, there may be issues. The Executor might read a field that you set in the constructor, even before the corresponding code in the constructor was executed. In general you should not expose this from inside a constructor. Java provides useful guarantees for objects after their constructor finished, but in order to benefit from those you have to wait for the result of new X(...) before using it.
Will this lead to any issues as we are trying to submit the object to
the executor even before creating it completely?
For one thing, you can get final variable that are still changing value - that is quite bad per the semantics of final. It can lead to very hard-to-trace concurrency bugs in multi-threaded code.
This code will usually print a few zeros and even the occasional 4, even though the final field a is only ever assigned the value 4 and should never been seen having any other value than 4.
public class A implements Runnable {
private static ExecutorService threads = Executors.newSingleThreadExecutor();
final int a;
public A() {
threads.execute(this);
Thread.yield();
a = 4;
}
#Override
public void run() {
if (a != 4) {
System.out.println(a);
}
}
public static void main(String[] args) {
for (int i = 0; i < 50_000; i++) {
new A();
}
threads.shutdown();
}
}
If the run() method is called even before all the initializing is done
(if at all it's possible), will the variables still be null which were
not yet initialized?
Yes, the ones not yet initialized will be null for reference variables, or the default value (0, false, '\0', 0d, 0f, etc.) for the primitive types. It is even possible according to the specifications with long and double fields to see only 32 of the 64 bits initialized (although on 64 bit architectures it is unlikely that you will ever observe this)
There will almost certainly be issues. What you have is called a "this escape" where you pass a this reference in a ctor to an external method. It's super bad, the object is incompletely constructed at that point and anything could happen.
What you should probably do instead is make the constructor private and use a factory method to get a new instance and execute it, if that's the goal.
public class A implements Runnable {
public A getNew() {
A a = new A();
Executors.newSingleThreadExecutor().execute(a);
return a;
}
private A() {
// some other initializations
}
}
I had some confusion about inner classes and lambda expression, and I tried to ask a question about that, but then another doubt arose, and It's probable better posting another question than commenting the previous one.
Straight to the point: I know (thank you Jon) that something like this won't compile
public class Main {
public static void main(String[] args) {
One one = new One();
F f = new F(){ //1
public void foo(){one.bar();} //compilation error
};
one = new One();
}
}
class One { void bar() {} }
interface F { void foo(); }
due to how Java manages closures, because one is not [effectively] final and so on.
But then, how come is this allowed?
public class Main {
public static void main(String[] args) {
One one = new One();
F f = one::bar; //2
one = new One();
}
}
class One { void bar() {} }
interface F { void foo(); }
Is not //2 equivalent to //1? Am I not, in the second case, facing the risks of "working with an out-of-date variable"?
I mean, in the latter case, after one = new One(); is executed f still have an out of date copy of one (i.e. references the old object). Isn't this the kind of ambiguity we're trying to avoid?
A method reference is not a lambda expression, although they can be used in the same way. I think that is what is causing the confusion. Below is a simplification of how Java works, it is not how it really works, but it is close enough.
Say we have a lambda expression:
Runnable f = () -> one.bar();
This is the equivalent of an anonymous class that implements Runnable:
Runnable f = new Runnable() {
public void run() {
one.bar();
}
}
Here the same rules apply as for an anonymous class (or method local class). This means that one needs to effectively final for it to work.
On the other hand the method handle:
Runnable f = one::bar;
Is more like:
Runnable f = new MethodHandle(one, one.getClass().getMethod("bar"));
With MethodHandle being:
public class MethodHandle implements Runnable {
private final Object object;
private final Method method;
public MethodHandle(Object object, java.lang.reflect.Method method) {
this.object = Object;
this.method = method;
}
#Override
public void run() {
method.invoke(object);
}
}
In this case, the object assigned to one is assigned as part of the method handle created, so one itself doesn't need to be effectively final for this to work.
Your second example is simply not a lambda expression. It's a method reference. In this particular case, it chooses a method from a particular object, which is currently referenced by the variable one. But the reference is to the object, not to the variable one.
This is the same as the classical Java case:
One one = new One();
One two = one;
one = new One();
two.bar();
So what if one changed? two references the object that one used to be, and can access its method.
Your first example, on the other hand, is an anonymous class, which is a classical Java structure that can refer to local variables around it. The code refers to the actual variable one, not the object to which it refers. This is restricted for the reasons that Jon mentioned in the answer you referred to. Note that the change in Java 8 is merely that the variable has to be effectively final. That is, it still can't be changed after initialization. The compiler simply became sophisticated enough to determine which cases will not be confusing even when the final modifier is not explicitly used.
The consensus appears to be that this is because when you do it using an anonymous class, one refers to a variable, whereas when you do it using a method reference, the value of one is captured when the method handle is created. In fact, I think that in both cases one is a value rather than a variable. Let's consider anonymous classes, lambda expressions and method references in a bit more detail.
Anonymous classes
Consider the following example:
static Supplier<String> getStringSupplier() {
final Object o = new Object();
return new Supplier<String>() {
#Override
public String get() {
return o.toString();
}
};
}
public static void main(String[] args) {
Supplier<String> supplier = getStringSupplier();
System.out.println(supplier.get()); // Use o after the getStringSupplier method returned.
}
In this example, we are calling toString on o after the method getStringSupplier has returned, so when it appears in the get method, o cannot refer to a local variable of the getStringSupplier method. In fact it is essentially equivalent to this:
static Supplier<String> getStringSupplier() {
final Object o = new Object();
return new StringSupplier(o);
}
private static class StringSupplier implements Supplier<String> {
private final Object o;
StringSupplier(Object o) {
this.o = o;
}
#Override
public String get() {
return o.toString();
}
}
Anonymous classes make it look as if you are using local variables, when in fact the values of these variables are captured.
In contrast to this, if a method of an anonymous class references the fields of the enclosing instance, the values of these fields are not captured, and the instance of the anonymous class does not hold references to them; instead the anonymous class holds a reference to the enclosing instance and can access its fields (either directly or via synthetic accessors, depending on the visibility). One advantage is that an extra reference to just one object, rather than several, is required.
Lambda expressions
Lambda expressions also close over values, not variables. The reason given by Brian Goetz here is that
idioms like this:
int sum = 0;
list.forEach(e -> { sum += e.size(); }); // ERROR
are fundamentally serial; it is quite difficult to write lambda bodies
like this that do not have race conditions. Unless we are willing to
enforce -- preferably at compile time -- that such a function cannot
escape its capturing thread, this feature may well cause more trouble
than it solves.
Method references
The fact that method references capture the value of the variable when the method handle is created is easy to check.
For example, the following code prints "a" twice:
String s = "a";
Supplier<String> supplier = s::toString;
System.out.println(supplier.get());
s = "b";
System.out.println(supplier.get());
Summary
So in summary, lambda expressions and method references close over values, not variables. Anonymous classes also close over values in the case of local variables. In the case of fields, the situation is more complicated, but the behaviour is essentially the same as capturing the values because the fields must be effectively final.
In view of this, the question is, why do the rules that apply to anonymous classes and lambda expressions not apply to method references, i.e. why are you allowed to write o::toString when o is not effectively final? I do not know the answer to that, but it does seem to me to be an inconsistency. I guess it's because you can't do as much harm with a method reference; examples like the one quoted above for lambda expressions do not apply.
No. In your first example you define the implementation of F inline and try to access the instance variable one.
In the second example you basically define your lambda expression to be the call of bar() on the object one.
Now this might be a bit confusing. The benefit of this notation is that you can define a method (most of the time it is a static method or in a static context) once and then reference the same method from various lambda expressions:
msg -> System.out::println(msg);
How can I make scope of a String variable(In Java) global.So that it is accessed from another function
Eg
//String b="null"; I don't want to do this... because if i do this, fun2 will print Null
public int func1(String s)
{
String b=s;
}
public int func2(String q)
{
System.out.println(b);//b should be accessed here and should print value of s
}
Any Help... Thanks
One of the fundamental concepts in OOP is the concept of scope: in almost all cases it is wise to reduce the scope of a variable (i.e. where it is visible from) to its minimum viable range.
I'm going to assume you absolutely require the use of that variable in both functions. Therefore, the minimum viable scope in this case would cover both functions.
public class YourClass
{
private String yourStringVar;
public int pleaseGiveYourFunctionProperNames(String s){
this.yourStringVar = s;
}
public void thisFunctionPrintsValueOfMyStringVar(){
System.out.println(yourStringVar);
}
}
Depending on the situation, you must assess the required scope of a variable, and you must understand the implications of increasing the scope (more access = potentially more dependencies = harder to keep track).
As an example, let's say you absolutely needed it to be a GLOBAL variable (as you call it in your question). A variable with Global scope can be accessed by anything within the application. This is exceptionally dangerous, which I will demonstrate.
To make a variable with global scope (there are no such things as global variables, exactly, in Java), you create a class with a static variable.
public class GlobalVariablesExample
{
public static string GlobalVariable;
}
If I were to alter the original code, it would now look like this.
public class YourClass
{
public int pleaseGiveYourFunctionProperNames(String s){
GlobalVariablesExample.GlobalVariable = s;
}
public void thisFunctionPrintsValueOfMyStringVar(){
System.out.println(GlobalVariablesExample.GlobalVariable);
}
}
This can be exceptionally powerful, and exceptionally dangerous as it can lead to weird behaviour that you do not expect, and you lose many of the abilities that object oriented programming gives you, so use it carefully.
public class YourApplication{
public static void main(String args[]){
YourClass instance1 = new YourClass();
YourClass instance2 = new YourClass();
instance1.pleaseGiveYourFunctionProperNames("Hello");
instance1.thisFunctionPrintsValueOfMyStringVar(); // This prints "Hello"
instance2.pleaseGiveYourFunctionProperNames("World");
instance2.thisFunctionPrintsValueOfMyStringVar(); // This prints "World"
instance1.thisFunctionPrintsValueOfMyStringVar(); // This prints "World, NOT Hello, as you'd expect"
}
}
Always assess the minimum viable scope for your variables. Do not make it more accessible than it needs to be.
Also, please don't name your variables a,b,c. And don't name your variables func1,func2. It doesn't make your application any slower, and it won't kill you to type in a few extra letters.
Hmm. You clearly need some lessons in object-oriented programming. In OO there is no "global" variable. But any variable defined as a member in a class (outside a method) is global within that class.
public class MyClass {
private String myVar; // this can be accessed everywhere in MyClass
public void func1(String s) {
myVar = s;
}
public void func2(String q) { // why is q needed here? It's not used
System.out.println(myVar);
}
}
So func2 will output the value of s ONLY IF you call func1 first.
final Myclass myClass = new MyClass();
myClass.func1("value");
myClass.func2("whatever"); // will output "value"
Also, why are the methods returning int in your example? They should be void.
I've heard about this happening in non thread-safe code due to improperly constructed objects but I really don't have the concept down, even after reading about in in Goetz's book. I'd like to solidify my understanding of this code smell as I maybe doing it and not even realize it. Please provide code in your explanation to make it stick, thanks.
Example : in a constructor, you create an event listener inner class (it has an implicit reference to the current object), and register it to a list of listener.
=> So your object can be used by another thread, even though it did not finish executing its constructor.
public class A {
private boolean isIt;
private String yesItIs;
public A() {
EventListener el = new EventListener() { ....};
StaticListeners.register(el);
isIt = true;
yesItIs = "yesItIs";
}
}
An additional problem that could happen later : the object A could be fully created, made available to all threads, use by another thread ... except that that thread could see the A instance as created, yesItIs with it "yesItIs" value, but not isIt! Believe it or not, this could happen ! What happen is:
=> synchronization is only half about blocking thread, the other half is about inter-thread visibility.
The reason for that Java choice is performance : inter-thread visibility would kill performance if all data would be shared with all threads, so only synchronized data is guaranteed to be shared...
Really simple example:
public class Test
{
private static Test lastCreatedInstance;
public Test()
{
lastCreatedInstance = this;
}
}
This is the reason why double-checked locking doesn't work. The naive code
if(obj == null)
{
synchronized(something)
{
if (obj == null) obj = BuildObject(...);
}
}
// do something with obj
is not safe because the assignment to the local variable can occur before the rest of the construction (constructor or factory method). Thus thread 1 can be in the BuildObject step, when thread 2 enters the same block, detects a non-null obj, and then proceeds to operate on an incomplete object (thread 1 having been scheduled out in mid-call).
public class MyClass{
String name;
public MyClass(String s)
{
if(s==null)
{
throw new IllegalArgumentException();
}
OtherClass.method(this);
name= s;
}
public getName(){ return name; }
}
In the above code, OtherClass.method() is passed an instance of MyClass which is at that point incompletely constructed, i.e. not yet fulfilling the contract that the name property is non-null.
Steve Gilham is correct in his assesment of why double checked locking is broken. If thread A enters that method and obj is null, that thread will begin to create an instance of the object and assign it obj. Thread B can possibly enter while thread A is still instantiating that object (but not completing) and will then view the object as not null but that object's field may not have been initialized. A partially constructed object.
However, the same type of problem can arrise if you allow the keyword this to escape the constructor. Say your constructor creates an instance of an object which forks a thread, and that object accepts your type of object. Now your object may have not be fully initialized, that is some of your fields may be null. A reference to your object by the one you have created in your constructor can now reference you as a non null object but get null field values.
A bit more explanation:
Your constructor can initialize every field in your class, but if you allow 'this' to escape before any of the other objects are created, they can be null (or default primative) when viewed by other threads if 1. They are not declared final or 2. They are not declared volatile
public class Test extends SomeUnknownClass{
public Test(){
this.addListner(new SomeEventListner(){
#Override
void act(){}
});
}
}
After this operation instanse of SomeEventListner will have a link to Test object, as a usual inner class.
More examples can be find here:
http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html
Here's an example of how uninitialized this of OuterClass can be accessed from inside of inner class:
public class OuterClass {
public Integer num;
public OuterClass() {
Runnable runnable = new Runnable() { // might lead to this reference escape
#Override
public void run() {
// example of how uninitialized this of outer class
// can be accessed from inside of inner class
System.out.println(OuterClass.this.num); // will print null
}
};
new Thread(runnable).start();
new Thread().start(); // just some logic to keep JVM busy
new Thread().start(); // just some logic to keep JVM busy
this.num = 8;
System.out.println(this.num); // will print 8
}
public static void main(String[] args) {
new OuterClass();
}
}
Output:
null
8
Pay attention to OuterClass.this.num instruction in the code