I am reading Java concurrency in practice and the below examples are from that. And my questions are What do they mean by this reference escape?. What will be the problem? . How does the this reference escapes from doSomething(e).
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
}
);
}
}
How does this solves the problem
public class SafeListener {
private final EventLis开发者_JAVA技巧tener listener;
private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
};
}
public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
Edit :
I have tried the below examples
public class Escape {
public Escape( Printer printer ){
printer.print(new Escaper(){
@Override
public void parentData(){
theCulprit1(Escape.this);
}
public String name = "shal";
@Override
public void theCulprit(){
System.out.println( this.name );
System.out.println( Escape.this.age );
}
});
canAccess();
}
public void canAccess(){
this.age = "25";
}
public String age = "62";
@SuppressWarnings("unused")
public static void main(String args[]){
Escape escape = new Escape(new Printer());
}
}
class Printer{
public void print(Escaper escaper){
escaper.theCulprit();
escaper.parentData();
}
}
class Escaper{
public void parentData(){
}
public void theCulprit(){
}
public void theCulprit1(Escape escape){
System.out.println(escape.age);
}
}
Due to incomplete construction of the escape object This outputs shal 62 62
Where as i changed my code like this
public class Escape {
private final Escaper escaper;
private Escape( ){
escaper = new Escaper(){
@Override
public void parentData(){
theCulprit1(Escape.this);
}
public String name = "shal";
public void theCulprit(){
System.out.println( name );
System.out.println( age );
}
};
canAccess();
}
public void canAccess(){
age = "25";
}
public String age = "62";
public static Escape newInstance( Printer printer){
Escape escape = new Escape();
printer.print(escape.escaper);
return escape;
}
@SuppressWarnings("unused")
public static void main(String args[]){
Escape.newInstance(new Printer());
}
}
Where as here.It outputs shal 25 25
Am i right ? Also is there any re-ordering of operations, because in the first example the age got initialized to 62. Even without making the escaper field final in my second example it works !
In the first form, the event listener object gets registered to the event source within the constructor, and thus it makes itself (and by association the "this" object) available to the event source before the constructor completes. If the inner class object escapes, so does the outer object.
Why is this a problem? Once the event listener is registered, the event source may invoke its methods at any time. Imagine a thread that the event source is using starts invoking the event listener methods. This now can happen even before the constructor completes.
This problem is worse than it appears, however, due to visibility issues. Even if you make the registration the "last operation" that the constructor does, there is still the possibility of seeing partially constructed object or an object in an invalid state. There is simply no visibility guarantee in the absence of a proper happens-before ordering.
Declaring it final affords that happens-before ordering (thus the second form).
when ever you have an inner class that is not static, like
class Outer {
class Inner {
}
}
the inner class has a hidden field that references the outer class, so you can imagine that it is like this
class Outer {
class Inner {
Outer hiddenOuter;
}
}
So whereever the inner object is used, the outer object is referenceable, and thus it's lifetime is at least as long as the inner object.
精彩评论