在Java 并发编程书里有个例子程序清单3-7 谈到 this escape。 开始没有想明白, 仔细琢磨了些时间发现代码主要的问题是在建构函数中创建了一个匿名类,然后发布了这个匿名类。
import java.util.*;
public class ThisEscape {
private final int num;
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
num = 42;
}
private void doSomething(Event e) {
if (num != 42) {
System.out.println("Race condition detected");
}
}
}
这段代码如果被 编译,然后JD-GUI 反编译看到得 doSomething(e); 就会变成
ThisEscape.this.doSomething(e); 这个应该是 java inner class 调用外部class的标准方式 - 外部类名.this.方法名
如果进一步的深究, 我们知道 ThisEscape编译后会有两个class 文件。一个是 ThisEscape.class, 另个一个会是 ThisEscape$1.class 给这个匿名类。
它们的内容差不多是这个样子的
public class ThisEscape {
private final int num;
public ThisEscape(EventSource source) {
source.registerListener(new ThisEscape$1(this));
num = 42;
}
private void doSomething(Event e) {
if (num != 42)
System.out.println(
"Race condition detected ");
}
static void access$000(ThisEscape _this, Event event) {
_this.doSomething(event);
}
}
class ThisEscape$1 implements EventListener {
final ThisEscape this$0;
ThisEscape$1(ThisEscape thisescape) {
this$0 = thisescape;
super();
}
public void onEvent(Event e) {
ThisEscape.access$000(this$0, e);
}
}
这样如果 new ThisEscape$1(this) 在另外的线程中被执行的话, 就可能导致 逃逸出去的this 的 num 还没有 执行 num = 42; Race condition detected 会不时的显示在console 里面。
结论 1, 就是不要在 建构函数随便创建匿名类然后 发布它们。
2, 不用再建构函数中随便起线程, 如果起要看有没有发布匿名类对象。
分享到:
相关推荐
this逃逸问题指的是在对象的构造函数还未完成时,其this引用就已经被其他线程获取并开始使用,这可能导致对象的状态不完整,进而引发不可预知的错误。 在Java中,对象的构造过程是线程安全的,也就是说,当构造函数...
2. **复制操作**:`dup`指令用于复制栈顶的引用,这样就有一个副本可以用来初始化`this`关键字,另一个则存储到方法中的变量。 3. **初始化**:`invokespecial`指令执行对象的构造函数,对实例变量进行初始化。这...
- **逃逸机制**:`##`用于插入注释,`#$`用于在输出中包含`$`字符。 - **内置指令**:Velocity提供了许多内置指令,如`#include`、`#parse`等,用于模板处理。 5. **最佳实践** - 避免使用可能导致混淆的变量...
构造器可以是默认的,也可以是用户自定义的,通过`this()`或`super()`调用来实现对父类构造器的调用。构造器的执行过程是在类的实例变量分配内存后进行的,确保对象在构造期间就已经有了合理的初始状态。 4. 对象的...
System.out.println("This is a final method."); } ``` 在类层次结构中,如果一个类被声明为`final`,则表示它不能被其他类继承。这有助于防止意外的改动和保护类的设计。例如: ```java public final class ...
确保编写的函数是面向对象的-类函数(例如Player和Enemy)或类原型函数(例如Enemy.prototype.checkCollisions),并在类和类原型函数中正确使用关键字“ this”引用调用该函数的对象。 安装游戏 下载或克隆存储库...
- 指令手册会列出所有这些指令,比如`iconst_5`表示将整数5压入操作数栈,`aload_0`用于将局部变量表的第一个元素(通常为this引用)加载到操作数栈。 3. **垃圾收集**: - JVM负责自动管理内存,通过垃圾收集...
可以是基本类型、字符串、属性引用、命令引用等,如`#set($monkey = $bill)`。支持数学运算,如加、减、乘、除和取模。 - **#if/#elseif/#else**:提供条件判断,根据条件执行不同的输出。例如: ```html #if ($...
- **this、super区别**:`this`指当前对象的引用,`super`指向父类的对象。 - **static用法**:用于声明静态变量、静态方法等,不依赖于对象存在。 - **面向对象、面向过程区别**:面向对象强调数据封装和对象交互;...
c) 在对象创建时正确初始化,避免`this`指针逃逸。 安全发布是确保线程安全的另一种方法,它是指在多线程环境中正确地暴露一个对象给其他线程。常见的安全发布方式包括: a) 通过静态初始化器创建对象,如`static ...
`final`关键字还可以影响JVM的优化,尤其是逃逸分析(Escape Analysis)。当JVM确定一个对象不会被外部访问时,可能会将其存储在栈上,从而提高效率。此外,对于`final`基本类型的局部变量,JVM可能会使用标量替换...
类是一种引用类型,具有更复杂的特性和行为,如继承、方法重写等: ```swift class Rectangle { var width: Double var height: Double init(width: Double, height: Double) { self.width = width self....