Java - Вызов для запуска метода на потоке: как это направляет к выполнению интерфейса Runnable ()?

Хорошо, я знаю два стандартных способа создать новый поток и выполнить его в Java:

  1. Реализация Runnable в классе определить run() метод и передача экземпляр класса к новому Thread. Когда start() метод на экземпляре потока называют, метод выполнения экземпляра класса будет вызван.

  2. Позвольте классу произойти из Thread, таким образом, это может для переопределения метода run() и затем когда новый экземпляр start() метод называют, вызов направлен к переопределенному методу.

В обоих методах, в основном новое Thread объект создается, и его метод запуска вызывается. Однако, в то время как во втором методе, механизме вызова, направленного к определяемому пользователем run() метод является очень четким, (это - простой полиморфизм во время выполнения в игре), я не понимаю как вызов к start() метод на объекте Потока направляется к run() метод реализации класса Runnable интерфейс. Делает Thread класс имеет частное поле Типа Runnable который это проверяет сначала, и если это установлено, затем вызывает метод выполнения, если это установило на объект? это было бы странным механизмом IMO.

Как делает вызов к start() на потоке направляются к методу выполнения Runnable интерфейс, реализованный классом, объект которого передается в качестве параметра при построении потока?

6
задан Gray 10 December 2013 в 20:44
поделиться

5 ответов

Поток сохраняет ссылку на экземпляр 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();
    }
}
7
ответ дан 9 December 2019 в 20:41
поделиться

В обоих случаях должен быть конкретный класс Thread. В первом случае (реализация Runnable) делает класс, который его реализует, способным «быть» потоком. Вам все равно нужно передать свой класс в качестве аргумента конструктору класса Thread. В то время как это не сценарий во втором случае, когда вы расширяете класс потока.

Когда вызывается метод start (), нет гарантии, что метод run () будет вызван немедленно. Вызов метода start () сообщает, что поток готов к запуску. После этого он может перейти в любое из состояний в зависимости от пула потоков.

К вашему сведению: класс Thread реализует Runnable

1
ответ дан 9 December 2019 в 20:41
поделиться

Вы могли только что проверить источник Thread.java , включенный как часть JDK:

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

, где цель:

private Runnable target;

Но я думаю, что настоящий ответ, который вы ищете, - это детали о том, как на самом деле работают потоки. К сожалению, это абстрагировано в собственных библиотеках. Просто постарайтесь получить общее представление о том, как работает многопоточность.

1
ответ дан 9 December 2019 в 20:41
поделиться

Единственная вещь, которая еще не исследована в ответах, - это то, как переходить от start () к run () , который одновременно и прост, и сложен.

Упрощенно говоря, метод start () вызывает собственный метод ( start0 в реализации OpenJDK), который выделяет некоторую память для нового стека и просит ОС запустить поток с этим пространством в качестве стека и с простой функцией C ++ ( thread_entry в реализации OpenJDK) в качестве функции реализации. Эта функция, в свою очередь, выполняет преобразование обратно в Java для вызова метода run () для объекта Thread. Шаблон на низком уровне (запрос ОС запустить новый поток в стеке и с функцией) должен быть знаком любому, кто выполняет собственные потоки в системах POSIX или Windows.

Детали делают все намного более сложным, со всей обработкой ошибок и неясными крайними случаями, которые необходимо обрабатывать. Если вам интересно, прочтите исходники OpenJDK , уделяя особое внимание Thread.java , JVM_StartThread в jvm.cpp и Класс JavaThread в thread.cpp и thread.hpp . Надеюсь, этот ответ дает вам достаточно подробностей, чтобы вы могли найти свой собственный путь ...

1
ответ дан 9 December 2019 в 20:41
поделиться

Хотя вы можете посмотреть на реальный исходный код, на вскидку это будет что-то вроде:

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, то метод run() MyThread будет просто делегирован методу run() этого Runnable.

2
ответ дан 9 December 2019 в 20:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: