Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java-在线程上调用start方法:它如何路由到可运行接口';运行()吗?_Java_Multithreading - Fatal编程技术网

Java-在线程上调用start方法:它如何路由到可运行接口';运行()吗?

Java-在线程上调用start方法:它如何路由到可运行接口';运行()吗?,java,multithreading,Java,Multithreading,好的,我知道创建新线程并在Java中运行它的两种标准方法: 在类中实现Runnable,定义run()。调用线程实例上的start()方法时,将调用类实例的run方法 让类从Thread派生,这样它就可以重写方法run(),然后当调用新实例的start()方法时,调用被路由到重写的方法 在这两种方法中,基本上都会创建一个新的线程对象,并调用其start方法。然而,在第二个方法中,调用路由到用户定义的run()方法的机制非常清楚(这是一个简单的运行时多态性),我不理解线程对象上对start()方法

好的,我知道创建新线程并在Java中运行它的两种标准方法:

  • 在类中实现
    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
    方法。