2012-05-26 3 views
8

Многопоточность в Java выполняется путем определения run() и вызова start().Как работает метод Java()?

Начать делегирование с помощью собственного метода, который запускает поток через подпрограммы операционной системы, и run() вызывается из этого недавно созданного потока.

При запуске автономного приложения основной поток создается автоматически для выполнения main().

Теперь рассмотрим этот код -

public class Test extends Thread { 
    public static void main(String[] args) throws Exception { 
     new Thread(new Test()).start(); 
     throw new RuntimeException("Exception from main thread"); 
    } 
    public void run() { 
     throw new RuntimeException("Exception from child thread"); 
    } 
} 

Это выход -

java.lang.RuntimeException: Exception from child thread 
    at com.Test.run(Test.java:11) 
    at java.lang.Thread.run(Thread.java:662) 
java.lang.RuntimeException: Exception from main thread 
    at com.Test.main(Test.java:8) 

Если главный() метод запускается через нить, почему не работает() появляется в верхней иерархии вызовов?

Как можно создать основную нить без внедрения Runnable?

+0

Чтобы уточнить, о чем вы спрашиваете: ваше ожидание, что 'main()' вызывается по-разному, когда его собственный класс реализует «Runnable»? (Потому что это не так.) – cheeken

ответ

4

Я не смотрел на внутренности JVM, но я бы предположил, что JVM создает основной поток для запуска основного метода, но запускает этот основной поток, вызывая собственный код напрямую, не проходя через классическую Java классы и методы для запуска потока.

+0

прямо на цель :) +1 – mprabhat

3

Главный метод запускается в отдельном потоке JVM, это родительский поток дочернего потока, вот почему вы не видите дочерний поток в верхней части иерархии вызовов.

Итак, в вашем случае JVM создал поток, запускающий вашу программу, которая также расширяет Thread.

Тогда в вашем основном методе вы создали новый экземпляр своего класса, который называется start on it. Это запустит новый поток, который является дочерним потоком, запущенным JVM для запуска вашей программы.

Поскольку основной метод является отправной точкой для автономной java-программы, это ответственность JVM за запуск в отдельном потоке, вы не записываете для него код.

При запуске программы путем вызова основного метода JVM не нуждается в том, чтобы быть потоком или реализовать Runnable, это стандартная процедура.

Описание от Inside Java Virtual Machine

Основной метод() начального класса приложений 'служит в качестве отправной точки для начального потока, который приложения. Начальная линия может, в свою очередь, отключать другие потоки.

В виртуальной машине Java потоки представлены в двух вариантах: daemon и не-демона. Нить демона обычно представляет собой поток, используемый самой виртуальной машиной , такой как поток, который выполняет сбор мусора . Однако приложение может отмечать любые потоки, которые он создает как потоки демона. Начальный поток приложения - тот, который начинается с main() - это поток не-демона.

Приложение для Java продолжает выполняться (экземпляр виртуальной машины продолжает жить), пока все потоки не-демона по-прежнему работают . Когда все не-демонные потоки приложения Java завершатся, экземпляр виртуальной машины выйдет. Если это разрешено администратором безопасности , приложение также может вызвать собственную кончину, вызвав метод exit() класса Runtime или System .

Иерархия вызовов не регулируется вами, она управляется основным планировщиком потоков.

Так, например, если я запускаю тот же код на моей машине Это выход

Exception in thread "main" java.lang.RuntimeException: Exception from main thread 
    at TestThread.main(TestThread.java:6) 
Exception in thread "Thread-1" java.lang.RuntimeException: Exception from child thread 
    at TestThread.run(TestThread.java:9) 
    at java.lang.Thread.run(Thread.java:662) 

так, когда вы запускали свой пример, планировщик выбрать отпустить ребенка нить, прежде чем основной.

Добавление к @JB Nizet, как будет вызываться программа или как будет реализован жизненный цикл потока, зависит от базовой ОС и аппаратного обеспечения, которая будет и будет меняться.

Никакие детали реализации не предоставили бы полного ответа, каждая реализация будет отличаться.

+1

прочитать обновление – mprabhat

+0

Это пара объясняет потоки демона и завершение потока. Не мой вопрос. >> «это стандартная процедура» Как реализуется стандартная процедура? –

+0

JVM выполняет сама реализация. Вы не можете дублировать его или что-то еще, это просто «волшебство». –

7

Если метод main() запускается через поток, почему не запускается() отображается вверху иерархии вызовов?

Как уже упоминалось, это связано с тем, что «основная» нить является специальной. Он не запускается через стандартные механизмы классов Thread, а вместо этого через код начальной загрузки Java. public static void main(String[] args) всегда управляется основным потоком из собственного кода.

Другое объяснение состоит в том, что на самом деле может быть метод run(), но способ, которым они строят стековый фрейм, скрывает его специально, чтобы не смущать пользователя. Например, поскольку вы делаете new Thread(new Test()), тогда ваш класс Test на самом деле является полем target внутри Thread. Когда фон Thread запущен, то он на самом деле вызывает Thread.run(), который имеет код:

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

Но мы никогда не видим метод Thread.run() в StackFrame, хотя кажется, что он должен быть там. Метод run()будет быть в стеке, если пользователь переопределит его в суперклассе Thread. Он может быть удален JDK для улучшения вывода стека.

Многопоточность в Java выполняется путем определения run() и вызова start().

Это правильно, но для потомков я думал, что важно понять, что у вашего кода есть проблема. Ваш класс Test должен не продлить Thread, но вместо этого должен быть реализован Runnable. Это работает, потому что Thread реализует Runnable.

Либо вы должны реализовать Runnable и изменить свой код, чтобы что-то вроде этого:

public class Test implements Runnable { 
    public static void main(String[] args) throws Exception { 
     new Thread(new Test()).start(); 
     throw new RuntimeException("Exception from main thread"); 
    } 
    public void run() { 
     throw new RuntimeException("Exception from child thread"); 
    } 
} 

Или вы все еще расширить Thread и изменить способ начать свой поток, чтобы что-то вроде следующего. Вышеуказанный шаблон Runnable рекомендуется, так как он позволяет вашей нитью Test расширить класс, если это необходимо.

public class Test extends Thread { 
    public static void main(String[] args) throws Exception { 
     new Test().start(); 
     throw new RuntimeException("Exception from main thread"); 
    } 
    @Override 
    public void run() { 
     throw new RuntimeException("Exception from child thread"); 
    } 
} 

Почему это важно? Текущий код на самом деле представляет собой объекты 2 Thread, но только один из них start() ed и работает как фон Thread. Вы могли бы иметь что-то вроде следующего: ошибка

public class Test extends Thread { 
    public static void main(String[] args) throws Exception { 
     Test test = new Test(); 
     new Thread(test).start(); 
     // this is not interrupting the background thread 
     test.interrupt(); 
0

Может быть, это семантический аргумент, но тема и процесс не являются синонимами.

Процесс запускается операционной системой и имеет собственные личные кодовые страницы (скомпилированный набор кода). A Thread запускается из внутренних программ, и изначально делится кодовыми страницами своего родителя (скомпилированным набором кода).

Что JVM внутренне использует Thread для запуска основного метода - это деталь реализации среды, но не представление языка Java. Если поток должен был сообщать в фреймах стека main, архитектура возврата назад к позиции исходного кода была бы невозможна, потому что этот основной поток не имел бы единицы компиляции (он является внутренним для JVM).