Java-在线程上调用start方法:它如何路由到可运行接口';运行()吗?
好的,我知道创建新线程并在Java中运行它的两种标准方法:Java-在线程上调用start方法:它如何路由到可运行接口';运行()吗?,java,multithreading,Java,Multithreading,好的,我知道创建新线程并在Java中运行它的两种标准方法: 在类中实现Runnable,定义run()。调用线程实例上的start()方法时,将调用类实例的run方法 让类从Thread派生,这样它就可以重写方法run(),然后当调用新实例的start()方法时,调用被路由到重写的方法 在这两种方法中,基本上都会创建一个新的线程对象,并调用其start方法。然而,在第二个方法中,调用路由到用户定义的run()方法的机制非常清楚(这是一个简单的运行时多态性),我不理解线程对象上对start()方法
Runnable
,定义run()。调用线程实例上的start()
方法时,将调用类实例的run方法
Thread
派生,这样它就可以重写方法run()
,然后当调用新实例的start()
方法时,调用被路由到重写的方法线程对象,并调用其start方法。然而,在第二个方法中,调用路由到用户定义的run()
方法的机制非常清楚(这是一个简单的运行时多态性),我不理解线程对象上对start()
方法的调用是如何路由到run()的
类实现Runnable
接口的方法。Thread
类是否有一个类型为Runnable
的私有字段,它首先检查该字段,如果设置了该字段,则在设置为对象时调用run方法?这将是一个奇怪的机制
在线程上对start()
的调用如何路由到由类实现的Runnable
接口的run方法,该类的对象在构造线程时作为参数传递?线程
保留对Runnable
实例的引用,并在run
的基本实现中调用它
您可以在源代码中看到这一点:
// passed into the constructor and set in the init() method
private Runnable target;
...
// called from native thread code after start() is called
public void run() {
if (target != null) {
target.run();
}
}
在这两种情况下,都必须有混凝土螺纹等级。在第一种情况下(实现Runnable),使实现它的类能够“成为”线程。您仍然必须将类作为参数传递给Thread类的构造函数。然而,在第二种情况下,扩展Thread类的情况并非如此
调用start()方法时,不能保证立即调用run()方法。调用start()方法表示线程已准备好运行。根据线程池程序的不同,它可以转到此后的任何状态
仅供参考:类线程实现可运行
您可以检查作为JDK一部分的线程的源代码
public void run() {
if (target != null) {
target.run();
}
}
其中目标是:
private Runnable target;
但是我认为你要寻找的真正答案是关于线程如何真正工作的细节。不幸的是,这在本机库中被抽象掉了。只要试着对线程是如何工作的有一个高层次的理解。虽然您可以查看实际的源代码,但猜测它可能是这样的:
public class MyThread implements Runnable {
private Runnable r;
public MyThread() {
}
public MyThread(Runnable r) {
this.r = r;
}
public void start() {
//magic to launch a new thread
run(); // the above magic would probably call run(), rather than
// call it directly here though.
}
public void run() {
if(r != null)
r.run();
}
}
简而言之,如果扩展MyThread并重写run(),则会调用run()方法。如果您传递了一个Runnable,MyThread的run()方法将委托给该Runnable的run()方法。答案中还没有探讨的一件事是如何从start()
到run()
,这既简单又复杂
简单化的术语,<代码> Stand()>代码>方法调用一个本地方法(OpenGJDK实现中的代码> Stest0),它为一个新堆栈分配一些内存,并要求OS以一个空间作为堆栈运行一个线程,并在OpenJDK实现中用一个简单的C++函数( TraceRead条目< /代码>)作为实现函数。该函数反过来将thunk返回到Java中,以调用Thread对象上的run()
方法。在POSIX系统或Windows中执行本机线程的任何人都应该熟悉低级模式(要求操作系统在堆栈上启动一个新线程并使用函数)
细节使这一切变得更加复杂,需要处理所有的错误处理和模糊的边缘情况。如果您感到好奇,请阅读源代码,特别注意JVM.cpp
中的Thread.java
、JVM\u StartThread
以及Thread.cpp
和Thread.hpp
中的JavaThread
类。希望这个答案能给你足够的细节,让你找到自己的路……想必这通常是第二种方法中提到的这个
?这并不能回答他的问题。如果从线程派生,则源代码中称为target的可运行引用为null。@Frederik:是的,但由于您重写了run
,因此不会对其产生任何影响。但我发现你的回答很容易被误解,因为你没有直接提到这一点。哦,仅供参考,我没有投你反对票。编辑:对不起。是我误解了OP的问题!被接受为答案,但看起来这意味着它是基于一个非常经验性的算法。如果对象恰好是线程的派生类,则将调用重写。否则默认值将检查是否设置引用并调用run()…我在想他们为什么这样做..这是任何模式吗?您的猜测完全正确,只是r
被称为target
,构造函数调用设置它的init
方法。