В чем разница между Thread start () и Runnable run ()

224

Скажем, у нас есть эти два Runnables:

class R1 implements Runnable {
    public void run() {  }
    
}

class R2 implements Runnable {
    public void run() {  }
    
}

Тогда какая разница между этим:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();

    r1.run();
    r2.run();
}

И это:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();
}
Ори Поповски
источник

Ответы:

309

Первый пример: нет нескольких потоков. Оба выполняются в одном (существующем) потоке. Нет создания темы.

R1 r1 = new R1();
R2 r2 = new R2();

r1и r2это просто два разных объекта классов, которые реализуют Runnableинтерфейс и, таким образом, реализуют run()метод. Когда вы звоните, r1.run()вы выполняете его в текущем потоке.

Второй пример: две отдельные темы.

Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);

t1и t2являются объектами класса Thread. Когда вы вызываете t1.start(), он запускает новый поток и вызывает run()метод r1внутри, чтобы выполнить его в этом новом потоке.

Беш Гурунг
источник
5
Может, я считаю, что до вызова Thread # start () ничего общего с потоком os не происходит? Это всего лишь объект Java.
Джаски
4
Это правильно в соответствии с документацией. Проверьте код инициализации объекта потока, который соответствует документации. Кроме того, в исходном коде это start()метод, который вызывает метод natvie, который должен вызывать связанные с потоком os вещи.
Беш Гурунг
3
Документы по созданию потоков находятся здесь . Источник инициализации объекта потока находится здесь . start()Источник метода здесь .
Беш Гурунг
92

Если вы просто вызываете run()напрямую, он выполняется в вызывающем потоке, как и любой другой вызов метода. Thread.start()требуется фактически создать новый поток, чтобы метод runnable runвыполнялся параллельно.

Майк Дэниелс
источник
2
В Hotspot JVM существует прямое сопоставление между потоком Java и собственным потоком. Thread.start()вызов заставляет состояние потока переходить из нового состояния в состояние Runnable . Runnable не означает, что поток работает. Как только собственный поток инициализирован, собственный поток вызывает run()метод в потоке Java, который изменяет состояние потока с Runnable на Running . Когда поток завершает работу, все ресурсы для нативного и Java-потока освобождаются.
сверхобмена
@overexchange Где я могу найти материал об изменении состояния.
twlkyao
73

Разница в том, что Thread.start()запускается поток, который вызывает run()метод, аRunnable.run() просто вызывается run()метод в текущем потоке.

Маркиз Лорн
источник
35

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

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

Джаймин Патель
источник
21

Фактически Thread.start()создает новый поток и имеет собственный сценарий выполнения.

Thread.start()вызывает run()метод асинхронно, что изменяет состояние нового потока на Runnable.

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

Если вы используете, Thread.run()то вы вообще не используете функции многопоточности.

адитйа
источник
8

invoke run()выполняется в вызывающем потоке, как и любой другой вызов метода. тогда как Thread.start()создает новый поток. вызов run()- это программная ошибка.

Нарендра Джагги
источник
7

Если вы используете run()метод main, поток метода main вызоветrun метод вместо потока, который требуется запустить.

start()Метод создает новый поток , и для которых run()метод должен сделать

Rohith
источник
«Основной метод» не имеет к этому никакого отношения.
Маркиз Лорн
3
@EJP под mainавтором подразумевал вызывающий метод. Его ответ довольно хороший. +1 ;-)
dom_beau
1
@dom_beau Если это то, что он имел в виду, он должен был так сказать. То, что он сказал, было неверным. В этом ответе нет ничего «хорошего». Это просто беспорядок.
Маркиз Лорн
5

t.start() это метод, который библиотека предоставляет для вашего кода для вызова, когда вы хотите новый поток.

r.run()это метод, который вы предоставляете для библиотеки для вызова в новом потоке.


Большинство из этих ответов пропустить большую картину, которая заключается в том, насколько языке Java обеспокоен, нет больше разницы между t.start()и r.run()чем между любыми двумя другими методами.

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

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

Итак, что же t.start()делать?

Он создает новый собственный поток, организует вызов этого потока t.run(), а затем сообщает ОС, чтобы новый поток работал. Тогда это возвращается.

А что делает r.run()?

Самое смешное, что тот, кто задает этот вопрос, тот, кто его написал . r.run()делает то, что вы (т.е. разработчик, который написал это) разработал для этого.

Соломон Медленный
источник
4

Thread.start()Код регистрирует поток с помощью планировщика, а планировщик вызывает run()метод. Также Threadесть класс, а Runnableесть интерфейс.

CHANDRAHAS
источник
3

С точки зрения участников все в порядке, поэтому я просто хочу кое-что добавить. Дело в том, что JAVA не поддерживает мульти-наследование. Но что делать, если вы хотите получить класс B из другого класса A, но вы можете получить только из одного класса. Теперь проблема заключается в том, как «извлечь» из обоих классов: A и Thread. Поэтому вы можете использовать Runnable Interface.

public class ThreadTest{
   public void method(){
      Thread myThread = new Thread(new B());
      myThread.start;
   }
}

public class B extends A implements Runnable{...
pommoisel
источник
хорошее объяснение метода run () с помощью примера о Runnable - интерфейсе и Thread - классе
Pinky Walve
1

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

Если вы вызываете start()метод в потоке, виртуальная машина Java будет вызывать метод run (), и одновременно будут выполняться два потока - текущий поток ( main()в вашем примере) и другой поток (запускаемый r1в вашем примере).

Посмотрите на исходный код start()метода в классе Thread

 /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
            stop0(throwableFromStop);
        }
    }

    private native void start0();

В приведенном выше коде вы не можете видеть вызов run()метода.

private native void start0()отвечает за вызов run()метода. JVM выполняет этот собственный метод.

Равиндра Бабу
источник
0

В первом случае вы просто вызов run()метода из r1и r2объектов.

Во втором случае вы фактически создаете 2 новых темы!

start()позвоню run()в какой то момент!

Марселлус Уоллес
источник
7
На самом деле, start () не будет вызывать run (): если это так, то метод run () будет выполняться тем же потоком, который вызвал start (). Функция start () создаст поток, который будет вызывать метод run ().
Бруно Рейс
0

запустить метод: - это абстрактный метод, первоначально созданный в интерфейсе Runnable и переопределенный в классе Thread, а также в подклассах Thread (поскольку поток реализует Runnable в его исходном коде) и любые другие реализующие классы интерфейса Runnable. - Он используется для загрузки потока (запускаемый объект) с задачей, для которой он предназначен, таким образом, вы переопределяете его, чтобы написать эту задачу.

Метод запуска: - определяется в классе Thread. Когда метод start вызывается для объекта Thread 1, он вызывает внутренне нативный (не Java) метод с именем start0 (); метод.

start0 (); method: отвечает за низкую обработку (создание стека для потока и выделение потока в очереди процессора), в этот момент у нас есть поток в состоянии Ready / Runnable.

2- В то время, когда планировщик потока решает, что поток входит в ядро ​​процессора в соответствии с (run threadable, а также алгоритмом планирования ОС), метод запускается для объекта Runnable (будь то текущий объект потока Runnable или переданный объект Runnable). в конструктор потока) здесь поток переходит в состояние выполнения и начинает выполнять свою задачу (метод run)

Эсраа Салама
источник
-2

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

Метод run () класса Thread ничего не делает, поэтому подклассы должны переопределить метод кодом, выполняемым во втором потоке. Если поток создается с аргументом Runnable, метод run () потока выполняет вместо этого метод run () объекта Runnable в новом потоке.

В зависимости от характера вашей многопоточной программы непосредственный вызов метода Thread run () может дать тот же результат, что и вызов метода start (), но в последнем случае код фактически выполняется в новом потоке.

gtzinos
источник
2
Вызов `run () 'не является способом создания многопоточных программ. Есть только один способ.
Маркиз Лорн
-2

Вызов метода Start () запускает метод переопределения расширенного класса Thread и реализует интерфейс Runnable.

Но вызывая run (), он ищет метод run, но если класс реализует интерфейс Runnable, он вызывает метод переопределения run () класса Runnable.

напр .:

`

public class Main1
{
A a=new A();
B b=new B();
a.run();//This call run() of Thread because run() of Thread only call when class 
        //implements with Runnable not when class extends Thread.
b.run();//This not run anything because no run method found in class B but it 
        //didn't show any error.

a.start();//this call run() of Thread
b.start();//this call run() of Thread
}

class A implements Runnable{
@Override
    public void run() {
            System.out.println("A ");
    }
}

class B extends Thread {

    @Override
    public void run() {
            System.out.println("B ");
    }
}

`

Анкит
источник