为什么'create'是异步的?

时间:2016-07-06 12:09:39

标签: java asynchronous instance

有人告诉我,创建新实例始终是异步消息;但我不明白为什么。

例如:

Foo myFoo = new Foo();

在这里,我将不得不等到构造函数完成并返回我的新对象。但不是异步意味着,我继续独立(没有等待) - 比如开始一个线程?

3 个答案:

答案 0 :(得分:4)

  

有人告诉我,创建新实例始终是异步消息;

对不起,我不得不说你听错了,或者你被告知错了。但首先,我们应该直截了当地获得一些术语。术语“异步”或“异步”表示调用会立即将返回给调用者。我们可以通过简单的实验[1]轻松证明构造函数不是这样。换句话说,构造函数必须返回给调用者以取得任何进展

启动线程确实是异步的。对Thread.start()的调用立即返回,并在稍后的某个时间点线程实际开始运行并执行run()方法。

1实验

考虑你的课程(仅供参考)如下:

Foo.java

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移交给另一个线程时,才能实现这一点。