根据StackOverflow的答案,start()
创建一个线程并在这个新线程中执行代码,run()
执行当前线程中的代码而不创建任何代码 - 就好像它是{{1} }}
但是文档,如果我理解正确的话,说Runnable
初始化一个新线程,如果你想在同一个线程中重新执行你的代码,你可以调用start()
哪一个是对的?
UPD
好的,看起来手动调用run()
并不是一个好习惯,至少没用。是否有一些很好的方法来调用run()
中的代码?比如,我经常需要一个相对缓慢的动作,一次一个实例 - 那么呢?
答案 0 :(得分:6)
如上所述, 他们都不对。
start
不会创建或初始化线程。它启动一个线程。来自the documentation:
使该线程开始执行; Java虚拟机调用此线程的run方法。
线程是创建并通过调用Thread
构造函数进行初始化,在调用start
之前,您必须自然地执行此操作。 (无论如何,这是“外部神话”;我必须检查JVM规范,但我怀疑JVM可能有效推迟实际创建OS线程,直到/除非你叫start
。)
在正常情况下,您永远不会直接调用run
实例的Thread
方法。相反,您通过start
启动线程,JVM在分配给该run
实例的实际线程上调度Thread
。如果直接调用run
,则会在您使用的线程上调用它,这可能不是分配给Thread
实例的线程。
您可能会发现Java concurrency tutorial有用。
重新评论以下内容:
如何重新执行
run()
中的代码?重新启动线程或者有一个控制执行的boolean
值的无限循环?
后者,但不是无限循环,具有终止条件的循环。来自start
文档:
不止一次启动线程永远不合法。特别是,一旦完成执行,线程可能无法重新启动。
所以一旦run
返回,那就是它,你不能继续使用该线程。相反,您的线程不会从run
返回,直到其工作完成。如果你想保持它等待工作,它应该等待某种信号量,你可以从线程外发出信号,唤醒它做一些工作。
上述教程的一个小节讨论了使用wait
和notify
/ notifyAll
与Guarded Blocks进行此操作的一种方法。
这是一个简单的例子,每次调用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");
}
}
示例输出:
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
。
答案 1 :(得分:3)
您的困惑可能来自于使用术语线程,创建和初始化。没有指明它们究竟解决了什么容易误解,因为有多个概念,术语 thread 用于描述。
一方面,有Thread对象(通过新的Thread(...)构造函数创建)。就实际执行任何事情而言,不是线程。它只是一个 facade ,用于实现标准化API与OS / VM交互的线程机制。
创建一个Thread实例基本上与创建任何其他java对象没有任何不同。没有任何事情与实际向OS线程调度程序添加线程有关。
OS端的线程实际上是在(私有)本机方法start0()中创建的,start()方法执行一些健全性检查,然后调用start0()来实际创建OS级别的线程。
所以行动的一般顺序是:
答案 2 :(得分:1)
这是start()和run()之间的主要区别:
Thread#start:当程序调用start()方法时,Java虚拟机会调用此线程的run方法。
Thread#run:如果直接调用run()方法,run()内的代码将在当前Thread上执行。
答案 3 :(得分:1)
如果我理解正确,说start()初始化一个新线程然后,如果你想在同一个线程中重新执行你的代码,你调用run()
这是不正确的。您需要了解每个Java程序都是使用 main 线程开始执行的。换句话说,当您运行具有main
方法的Java程序(例如java MyProgram)时,将使用此堆栈底部的main
方法创建新的执行堆栈。
如果程序在Thread
方法中创建main
实例并在线程实例上调用start
方法,则将使用run
创建新的执行堆栈堆栈底部的方法。您现在将拥有两个执行堆栈。一个在堆栈底部使用main
方法,另一个在堆栈底部使用run
方法。这两个堆栈可以并行完成它们的执行。
另一方面,如果在run
方法中的线程实例上调用main
,则只需在与main
方法相同的执行堆栈中调用它。不会创建新的执行堆栈。因此,在线程实例上调用run
与在任何其他对象上调用任何其他方法一样好,并且没有特殊含义。