有人告诉我,创建新实例始终是异步消息;但我不明白为什么。
例如:
Foo myFoo = new Foo();
在这里,我将不得不等到构造函数完成并返回我的新对象。但不是异步意味着,我继续独立(没有等待) - 比如开始一个线程?
答案 0 :(得分:4)
有人告诉我,创建新实例始终是异步消息;
对不起,我不得不说你听错了,或者你被告知错了。但首先,我们应该直截了当地获得一些术语。术语“异步”或“异步”表示调用会立即将返回给调用者。我们可以通过简单的实验[1]轻松证明构造函数不是这样。换句话说,构造函数必须返回给调用者以取得任何进展。
启动线程确实是异步的。对Thread.start()
的调用立即返回,并在稍后的某个时间点线程实际开始运行并执行run()
方法。
考虑你的课程(仅供参考)如下:
class Foo {
Foo() throws InterruptedException {
while (true) {
System.out.println("not returning yet ...");
Thread.sleep(2000);
}
}
public static void main(String[] args) throws InterruptedException {
Foo foo = new Foo();
}
}
如果您编译并运行此类(我在Mac上使用Java 8,但这不是必需的)。正如所料,这个类每2秒运行一次产生输出:
not returning yet ...
not returning yet ...
not returning yet ...
not returning yet ...
请注意,添加sleep
调用只是为了让它可以忍受。你可以尝试这个实验而不用它,但是你的程序将通过强调100%来压倒其中一个CPU。
如果,当它正在运行时,你进行了一个线程转储(例如,使用命令jstack
),你会看到类似下面的东西(为了简洁而缩减):
"main" #1 prio=5 os_prio=31 tid=0x00007f9522803000 nid=0xf07
waiting on condition [0x000000010408f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at Foo.<init>(Foo.java:5)
at Foo.main(Foo.java:9)
无论线程的状态如何(RUNNABLE, BLOCKED, WAITING, TIMED_WAITING
),您总会看到(采取各种线程转储以查看这意味着什么),您将始终看到这两行:
at Foo.<init>(Foo.java:5)
at Foo.main(Foo.java:9)
这意味着调用者(在这种情况下,main thread
)永远不会取得任何进展。由于此构造函数永远不会返回,因此不会发生任何进展。
答案 1 :(得分:0)
有人告诉我,创建新实例始终是异步消息;
不,java构造函数没有暗示同步。无论如何,你可以在其中遇到并发问题。在构造函数调用之后,无法保证所有字段都已初始化。
在这里,我将不得不等到构造函数完成并返回我的新对象。但不是异步的意思,我继续独立(没有等待) - 比如开始一个线程?
不,你不必等待。您可以在另一个线程中访问该对象。
我建议你阅读thread。
答案 2 :(得分:0)
构造函数仍在执行时并发访问对象的示例:
public class Demo {
private volatile int constructionCounter;
private volatile String string;
public Demo() throws InterruptedException {
super();
assert this.constructionCounter == 0;
this.constructionCounter++;
// From this point on, there's no way the constructionCounter can ever be != 1 again, because the constructor will never run more than once, concurrently or otherwise.
assert this.constructionCounter == 1;
final Demo newInstance = this;
Thread t = new Thread( new Runnable() {
public void run() {
// Access new instance from another thread.
// Race condition here; may print "Hello null" or "Hello World" depending on whether or not the constructor already finished.
System.out.println("Hello " + newInstance.getString());
}
});
t.start();
this.setString( "World!" );
}
public String setString( String str ) {
this.string = str;
}
public String getString() {
return this.string;
}
}
请注意,只有当构造函数本身以某种方式将this
移交给另一个线程时,才能实现这一点。