7

或者是吗?
我有一个来自以下的线程对象:

Thread myThread = new Thread(pObject);

其中 pObject 是实现 Runnable 接口的类的对象,然后我在线程对象上调用了 start 方法,如下所示:

myThread.start();

现在,我的理解是,当 start() 被调用时,JVM 隐式(并立即)调用可能被覆盖的 run() 方法(就像我的情况一样)

但是,在我的情况下,似乎 start() 方法没有立即调用(根据需要),而是直到其他语句/方法从调用块完成,即如果我在 start() 调用之后有一个方法,如下所示:

myThread.start();
doSomethingElse();

doSomthingElse() 在 run() 方法运行之前被执行。
也许我对 run() 总是在 start() 被调用后立即调用的初始前提是错误的。请帮忙!再次需要的是在 start() 之后立即执行 run()。谢谢。

4

6 回答 6

16

嗯...该run()方法将在不同的线程中运行。根据定义,这意味着您不能对当前线程中将执行哪些语句之前或之后做出任何假设,除非您明确同步它们。

于 2010-04-22T11:14:12.977 回答
13

run()是代码中新线程执行的第一件事,但是新线程首先执行一些设置工作,并且不能保证在原始线程继续之前新线程会完成任何大量工作打电话doSomethingElse()

您认为这里没有保证是正确的。对多线程代码的行为做出假设是很多痛苦的根源——尽量不要这样做!

于 2010-04-22T11:12:38.387 回答
12

现在,我的理解是,当 start() 被调用时,JVM 隐式(并立即)调用 run() 方法......

这是不正确的。它确实隐式调用run(),但调用不一定立即发生。

现实情况是,新线程可以在start()调用后的某个时间点进行调度。实际调度取决于本机调度程序。它可能会立即发生,或者父线程可能会在子线程被调度之前持续一段时间。

要强制您的线程立即开始运行(或者更准确地说,在之前开始运行doSomethingElse()),您需要进行一些显式同步;例如这样的:

    java.util.concurrent.CountDownLatch latch = new CountdownLatch(1);
    new Thread(new MyRunnable(latch)).start();
    latch.await(); // waits until released by the child thread.
    doSomethingElse();

在哪里

class MyRunnable implements Runnable {
    private CountDownLatch latch;
    MyRunnable (CountDownLatch latch) { this.latch = latch; }
    public void run() {
        doSomeStuff();
        latch.countDown(); // releases the parent thread
        doSomeMoreStuff();
    }
    ...
}

还有其他方法可以使用并发类或 Java 的 mutex/wait/notify 原语1来实现同步。但是两个线程之间的显式同步是保证您需要的行为的唯一方法。

请注意,子线程中的调用会在父线程释放之前完成,但对于anddoSomething()的执行顺序我们无话可说。(一个可能在另一个之前运行,反之亦然,或者它们可能并行运行。)doSomethingElese()doSomeMoreStuff()


1 - 不推荐使用wait/ notify,但如果并发 API 不可用,它可能是您唯一的选择;例如在 Java ME 上。

于 2010-04-22T11:50:39.270 回答
6

当您调用 时myThread.start(),您的线程变得可用于执行。它是否会真正获得 CPU,以及持续多长时间——这取决于操作系统调度程序。事实上,您run()可能会立即获得控制权,但在它可以做任何您能注意到的事情之前就失去了控制权。确保您的线程执行您之前需要的唯一方法doSomethingElse()是使用显式同步。

于 2010-04-22T11:19:52.713 回答
3

您已经开始了一个新线程。该线程与启动它的线程并行运行,因此顺序可能是:

pObject.run();
doSomethingElse();

或者

doSomethingElse();
pObject.run();

或者,更有可能的是,会有一些交叉。pObject.run()可能在中间运行,doSomethingElse()反之亦然,或者一个将在另一个完成之前开始,依此类推。理解这一点并理解原子操作的含义很重要,否则您会发现自己遇到了一些非常难以发现的错误。

如果两个或多个线程访问相同的变量,情况会更加复杂。在某些情况下,一个线程中的值可能永远不会在一个线程中更新。

我强烈建议:

  1. 除非绝对需要,否则不要让程序多线程;和

  2. 如果您这样做,请购买并从头到尾阅读 Brian Goetz 的Java Concurrency in Practice

于 2010-04-22T11:16:32.800 回答
0

在线程对象上调用 start 方法可能不会使 jvm 立即调用 run() 方法,而是使线程可运行并准备好执行,在这种情况下,父线程首先执行其代码,然后将控制权传递给子线程线程,如果您希望子线程在父线程代码执行之前执行,请使用父线程中的 chileThreadObject.join() 方法。

于 2018-10-23T23:25:43.410 回答