需要对Java线程做一些澄清:start()和run()

Ale*_*lex 1 java multithreading

根据StackOverflow的答案,start()创建一个线程并在这个新线程中run()执行代码并在当前线程中执行代码而不创建任何代码 - 就像它是一个Runnable

但是文档,如果我理解它们,就说start()初始化一个新线程,如果你想在同一个线程中重新执行你的代码,你调用run()

哪一个是对的?

UPD

好吧,看起来像run()手动调用不是一个好习惯,至少是无用的.是否有一些很好的方法来调用代码run()?比如,我经常需要一个相对慢的动作,一次一个实例 - 那么呢?

T.J*_*der 6

引,没有人是正确的.

start不创建或初始化线程.它开始一个线程.从文档:

导致此线程开始执行; Java虚拟机调用此线程的run方法.

通过调用构造函数来创建和初始化线程Thread,这在调用之前通常需要执行start.(无论如何,那是"外部神话";我必须检查JVM规范,但我怀疑JVM推迟实际创建OS线程可能是有效的,直到/除非你调用start.)

在正常情况下,您永远不会直接调用实例的run方法Thread.相反,您启动线程start,JVM调度run分配给该Thread实例的实际线程.如果run直接调用,它会在你用来执行该操作的线程上调用,这可能不是分配给Thread实例的线程.

您可能会发现Java并发教程很有用.


你的评论如下:

以及如何重新执行代码run()?重新启动线程或者有一个带有boolean控制执行值的无限循环?

后者,但不是无限循环,具有终止条件的循环.从start文档:

不止一次启动一个线程永远不合法.特别是,一旦完成执行,线程可能无法重新启动.

所以一旦run返回,那就是它,你不能继续使用该线程.相反,你有线程不会返回,run直到它的工作完成.如果你想保持它等待工作,它应该等待某种信号量,你可以从线程外发出信号,唤醒它做一些工作.

上面教程的一个小节讨论了使用和/来保护块的一种方法.waitnotifynotifyAll


这是一个简单的例子,每次调用都会System.out.println打印出调用的线程的名称,这样你就可以看到哪个线程做了什么:

实时复制

class Example
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Thread t= new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + ": Running run");
            }
        });
        System.out.println(Thread.currentThread().getName() + ": Running main");
        System.out.println(Thread.currentThread().getName() + ": Calling t.start()");
        t.start();
        System.out.println(Thread.currentThread().getName() + ": Calling t.join() to wait for thread exit");
        try {
            t.join();
        } catch (InterruptedException ie) {
            System.out.println(Thread.currentThread().getName() + ": Calling got InterruptedException");
        }
        System.out.println(Thread.currentThread().getName() + ": Program complete");
    }
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

main: Running main
main: Calling t.start()
main: Calling t.join() to wait for thread exit
Thread-0: Running run
main: Program complete

注意我们的主线程刚刚调用start; 然后JVM进行设置,以便run在我们创建的线程上调用.