为什么在java中的线程对象上调用start()时不会立即调用run()

时间:2010-04-22 11:10:25

标签: java multithreading runnable

或者是吗? 我有一个来自的对象:

Thread myThread = new Thread(pObject);

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

myThread.start();

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

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

myThread.start();
doSomethingElse();

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

6 个答案:

答案 0 :(得分:16)

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

答案 1 :(得分:13)

run()是你的代码中新线程所做的第一件事,但是新线程首先做了一些设置工作,而且不能保证任何大量的工作都将由原始线程继续调用doSomethingElse()之前的新线程。

你认为这里没有保证你是对的。对多线程代码的行为做出假设是非常痛苦的根源 - 尽量不要这样做!

答案 2 :(得分:11)

  

现在,我的理解是当调用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的互斥/等待/通知原语 1 来实现同步。但是,两个线程之间的显式同步是保证所需行为的唯一方法。

请注意,子线程中的doSomething()调用将在父线程发布之前完成,但我们不能说明doSomethingElese()doSomeMoreStuff()的执行顺序。 (一个可能在另一个之前运行,反之亦然,或者它们可能并行运行。)


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

答案 3 :(得分:6)

当您致电myThread.start()时,您的线程可供执行。它是否会实际获得CPU,以及多长时间 - 它是OS调度程序。实际上,您的run()可能会立即获得控制权,但在它可以执行您可以注意到的任何操作之前丢失它。确保线程在doSomethingElse()之前执行所需操作的唯一方法是使用显式同步。

答案 4 :(得分:3)

你已经开始了新的主题。该线程与启动它的线程并行运行,因此顺序可以是:

pObject.run();
doSomethingElse();

doSomethingElse();
pObject.run();

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

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

我强烈建议:

  1. 使你的程序多线程,除非绝对需要;以及

  2. 如果你这样做,请购买并阅读封面以覆盖Brian Goetz的Java Concurrency in Practice

答案 5 :(得分:0)

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