Java - 调用在线程上启动方法:它如何路由到Runnable接口的run()?

时间:2010-04-07 22:42:33

标签: java multithreading

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

  1. 在类中实现Runnable,定义run()方法,并将类的实例传递给新的Thread。当调用线程实例上的start()方法时,将调用类实例的run方法。

  2. 让类派生自Thread,因此它可以覆盖方法run(),然后在调用新实例的start()方法时,将调用路由到覆盖方法

  3. 在这两种方法中,基本上都会创建一个新的Thread对象并调用其start方法。但是,在第二种方法中,调用的机制被路由到用户定义的run()方法非常清楚,(这是一个简单的运行时多态性),我不明白如何调用{{ Thread对象上的方法被路由到实现start()接口的类的run()方法。 Runnable类是否具有首先检查的类型Thread的私有字段,如果已设置,则调用run方法(如果设置为对象)?这将是一个奇怪的机制IMO。

    线程上对Runnable的调用如何被路由到类的实现的start()接口的run方法,该类的对象在构造线程时作为参数传递?

5 个答案:

答案 0 :(得分:7)

Thread保留对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();
    }
}

答案 1 :(得分:2)

虽然您可以查看实际的源代码,但猜测它会是:

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()方法。

答案 2 :(得分:1)

在这两种情况下都必须有具体的Thread类。在第一种情况下(实现Runnable),使实现它的类能够“成为”一个线程。您仍然必须将您的类作为参数传递给Thread类的构造函数。而那不是第二种情况下扩展线程类的场景。

调用start()方法时,无法保证立即调用run()方法。调用start()方法可以告诉线程已准备好运行。此后它可以进入任何状态,具体取决于Thread pooler。

仅供参考:class Thread implements Runnable

答案 3 :(得分:1)

您刚刚检查了JDK中包含的Thread.java的来源:

public void run() {
    if (target != null) {
        target.run();
    }
}

目标是:

private Runnable target;

但我认为你正在寻找的真正答案是关于线程如何真正起作用的细节。不幸的是,这在本地图书馆中被抽象出来了。试着深入了解线程的工作原理。

答案 4 :(得分:1)

答案尚未探讨的一件事是事情如何从start()传递到run(),同时既简单又复杂。

简单来说,start()方法调用OpenJDK实现中的本机方法(start0),为新堆栈分配一些内存,并要求操作系统将该空间作为堆栈运行并使用普通的C ++函数(OpenJDK实现中的thread_entry)作为实现函数。该函数反过来将thunk返回到Java以调用Thread对象上的run()方法。在POSIX系统或Windows中执行本机线程的任何人都应该熟悉低级别的模式(要求操作系统在堆栈上启动新线程并使用函数)。

细节使得它变得更加复杂,需要处理所有错误处理和模糊的边缘情况。如果您感到好奇,请阅读OpenJDK来源,特别关注Thread.java中的JVM_StartThreadjvm.cpp中的JavaThread以及thread.cpp中的thread.hpp课程和{{1}}。希望这个答案能为您提供足够的细节,让您找到自己的方式......