繁体   English   中英

为什么在Java中的线程对象上调用start()时没有立即调用run()

[英]Why is run() not immediately called when start() called on a thread object in java

还是?
我有一个来自的线程对象:

Thread myThread = new Thread(pObject);

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

myThread.start();

现在,我的理解是,当调用start()时,JVM隐式(立即)调用了run()方法,该方法可能会被覆盖(就我而言)

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

myThread.start();
doSomethingElse();

doSomthingElse()在运行run()方法之前就已执行。
最初的前提是总是在调用start()之后立即调用run()可能使我错了。 请帮忙! 再次希望在start()之后立即执行run()。 谢谢。

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

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

您认为这里没有保证是正确的。 对多线程代码的行为进行假设是造成很多痛苦的根源,请不要这样做!

现在,我的理解是,当调用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上。

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

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

pObject.run();
doSomethingElse();

要么

doSomethingElse();
pObject.run();

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

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

我强烈建议:

  1. 除非绝对必要,否则不要使程序成为多线程。

  2. 如果您愿意,请从封面开始阅读并阅读,以涵盖Brian Goetz的Java Concurrency in Practice

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM