假设我们有这两个Runnables:
class R1 implements Runnable {
public void run() { … }
…
}
class R2 implements Runnable {
public void run() { … }
…
}
那么这有什么区别:
public static void main() {
R1 r1 = new R1();
R2 r2 = new R2();
r1.run();
r2.run();
}
还有这个:
public static void main() {
R1 r1 = new R1();
R2 r2 = new R2();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
14 回答
First example: 没有多线程 . 两者都在单个(现有)线程中执行 . 没有线程创建 .
r1
和r2
只是实现Runnable
接口的两个不同的类对象,因此实现了run()
方法 . 当您调用r1.run()
时,您正在当前线程中执行它 .Second example: 两个单独的线程 .
t1
和t2
是类Thread
的对象 . 当你调用t1.start()
时,它会启动一个新线程并在内部调用r1
的run()
方法在该新线程中执行它 .如果你只是直接调用
run()
,它就会在调用线程上执行,就像任何其他方法调用一样 . 需要Thread.start()
来实际创建一个新线程,以便并行执行runnable的run
方法 .区别在于
Thread.start()
启动一个调用run()
方法的线程,而Runnable.run()
只调用当前线程上的run()
方法 .difference 是当程序调用
start()
方法时,创建 new 线程并且run()
中的代码在 new 线程中执行,而如果直接调用run()
方法,将创建 no new thread并且run()
内的代码将直接在当前线程中执行 .Java线程中
start()
和run()
之间的另一个 difference 是你 can not 两次调用start()
. 一旦启动,第二次start()
调用将在Java中抛出IllegalStateException
,而您可以多次调用run()
方法,因为它只是一个 ordinary 方法 .实际上
Thread.start()
创建了一个新线程并拥有自己的执行场景 .Thread.start()
异步调用run()
方法,这会将新Thread的状态更改为Runnable .但
Thread.run()
不会创建任何新线程 . 相反,它同步执行当前运行线程中的run方法 .如果您使用的是
Thread.run()
,那么您根本就没有使用多线程的功能 .调用
run()
正在调用线程上执行,就像任何其他方法调用一样 . 而Thread.start()
创建一个新线程 . 调用run()
是一个程序化错误 .如果在main方法中执行
run()
,则main方法的线程将调用run
方法而不是运行所需的线程 .start()
方法创建新线程,并且必须为其执行run()
方法Thread.start()
代码使用调度程序注册线程,调度程序调用run()
方法 . 此外,Thread
是类,而Runnable
是接口 .大多数这些答案都错过了大局,就Java语言而言,
t.start()
和r.run()
之间的区别与其他两种方法之间没有区别 .他们都只是方法 . 它们都在调用它们的线程中运行 . 他们都做了他们编码做的任何事情,然后他们都在同一个线程中返回给他们的呼叫者 .
最大的区别是
t.start()
的大多数代码都是本机代码,而在大多数情况下,r.run()
的代码将是纯Java . 但是's not much of a difference. Code is code. Native code is harder to find, and harder to understand when you find it, but it'仍然只是代码告诉计算机该做什么 .那么,
t.start()
做什么?它创建一个新的本机线程,它安排该线程调用
t.run()
,然后它告诉操作系统让新线程运行 . 然后它返回 .r.run()
做了什么?有趣的是,提出这个问题的人是写这个问题的人 .
r.run()
做任何你(即编写它的开发人员)设计它做的事情 .t.start()
是库为您的代码在需要新线程时调用的方法 .r.run()
是您为库在新线程中调用提供的方法 .成员们提出的要点是正确的,所以我只想添加一些内容 . 问题是JAVA不支持多继承 . 但是,如果你想从另一个A类派生一个B类,但是你只能从一个Class派生出来 . 现在的问题是如何从两个类“派生”:A和Thread . 因此,您可以使用Runnable接口 .
如果直接调用
run()
方法,则表示您没有使用自run()
方法作为调用者线程的一部分执行以来的多线程功能 .如果在Thread上调用
start()
方法,Java虚拟机将调用run()方法,并且两个线程将同时运行 - 当前线程(在您的示例中为main()
)和其他线程(在您的示例中为Runnabler1
) .看看Thread class中
start()
方法的源代码在上面的代码中,您无法看到对
run()
方法的调用 .private native void start0()
负责调用run()
方法 . JVM执行此本机方法 .在第一种情况下,您只是调用
r1
和r2
对象的run()
方法 .在第二种情况下,你实际上创建了2个新线程!
start()
会在某个时候调用run()
!Start()方法调用Thread扩展类的run override方法和Runnable实现接口 .
但是通过调用run()它会搜索run方法但是如果类实现了Runnable接口,那么它调用Run()的run()覆盖方法 .
例:
`
`
Thread类中的单独start()和run()方法提供了两种创建线程程序的方法 . start()方法开始执行新线程并调用run()方法 . start()方法立即返回,新线程通常会继续,直到run()方法返回 .
Thread类的run()方法不执行任何操作,因此子类应该使用代码覆盖该方法以在第二个线程中执行 . 如果使用Runnable参数实例化Thread,则线程的run()方法将在新线程中执行Runnable对象的run()方法 .
根据线程程序的性质,直接调用Thread run()方法可以提供与通过start()方法调用相同的输出,但在后一种情况下,代码实际上是在新线程中执行的 .