Qual é a diferença entre Thread start () e Runnable run ()

224

Digamos que temos esses dois Runnables:

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

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

Então qual é a diferença entre isso:

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

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

E isto:

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();
}
Ori Popowski
fonte

Respostas:

309

Primeiro exemplo: sem vários threads. Ambos são executados em um único thread (existente). Nenhuma criação de thread.

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

r1e r2são apenas dois objetos de classes diferentes que implementam a Runnableinterface e, portanto, implementam o run()método Quando você liga, r1.run()está executando no thread atual.

Segundo exemplo: dois segmentos separados.

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

t1e t2são objetos da classe Thread. Quando você chama t1.start(), ele inicia um novo thread e chama o run()método r1internamente para executá-lo nesse novo thread.

Bhesh Gurung
fonte
5
Couuld Considero que, antes de chamarmos o Thread # start (), nada realmente relativo ao thread do OS acontece? É apenas um objeto java.
Jaskey
4
Isso está correto de acordo com a documentação. Verifique o código de inicialização do objeto de encadeamento, que está em conformidade com a documentação. Também no código fonte, é o start(), que está chamando um método natvie, que deve estar fazendo com que as coisas relacionadas ao thread do sistema aconteçam.
Bhesh Gurung 28/05
3
A documentação do construtor de threads está aqui . A origem de inicialização do objeto Thread está aqui . start()A fonte do método está aqui .
Bhesh Gurung
92

Se você simplesmente chamar run()diretamente, ele será executado no segmento de chamada, como qualquer outra chamada de método. Thread.start()é necessário para realmente criar um novo encadeamento para que o runmétodo do executável seja executado em paralelo.

Mike Daniels
fonte
2
No Hotspot JVM, há um mapeamento direto entre o encadeamento java e o encadeamento nativo. Thread.start()chamada faz com que o estado do encadeamento se mova do novo estado para o estado Runnable . Runnable não significa que o thread esteja em execução. Depois que o encadeamento nativo foi inicializado, o encadeamento nativo invoca o run()método no encadeamento Java, que altera o estado do encadeamento de Runnable para Running . Quando o encadeamento termina, todos os recursos para o encadeamento nativo e Java são liberados.
overexchange
@overexchange Onde posso encontrar o material sobre a mudança de estado.
Twlkyao
73

A diferença é que Thread.start()inicia um thread que chama o run()método, enquanto Runnable.run()apenas chama o run()método no thread atual.

Marquês de Lorne
fonte
35

A diferença é que, quando o programa chama o start()método, um novo thread é criado e o código interno run()é executado no novo thread; se você chamar o run()método diretamente, nenhum novo thread será criado e o código interno run()será executado diretamente no thread atual.

Outra diferença entre start()e run()no encadeamento Java é que você não pode chamar start()duas vezes. Uma vez iniciada, a segunda start()chamada será lançada IllegalStateExceptionem Java enquanto você pode chamar o run()método várias vezes, pois é apenas um método comum .

Jaimin Patel
fonte
21

Na verdade, Thread.start()cria um novo encadeamento e tem seu próprio cenário de execução.

Thread.start()chama o run()método de forma assíncrona, que altera o estado do novo Thread para Runnable.

Mas Thread.run()não cria nenhum novo thread. Em vez disso, execute o método run no atual thread em execução de forma síncrona.

Se você estiver usando Thread.run(), não estará usando os recursos do multi threading.

aditya
fonte
8

invoke run()está sendo executado no thread de chamada, como qualquer outra chamada de método. ao passo que Thread.start()cria um novo thread. invocar run()é um erro programático.

Narendra Jaggi
fonte
7

Se você fizer isso run()no método principal, o encadeamento do método principal chamará o runmétodo em vez do encadeamento que você precisa executar.

O start()método cria um novo encadeamento e para o qual o run()método deve ser feito

Rohith
fonte
O 'método principal' não tem nada a ver com isso.
Marquês de Lorne
3
@EJP, pelo mainescritor significava o método de chamada. Sua resposta é muito boa. 1 ;-)
dom_beau
1
@dom_beau Se é isso que ele quis dizer, ele deveria ter dito isso. O que ele disse estava incorreto. Não há nada "muito bom" nessa resposta. É apenas uma bagunça confusa.
Marquês de Lorne #
5

t.start() é o método que a biblioteca fornece para o seu código chamar quando você deseja um novo thread.

r.run()é o método que você fornece para a biblioteca chamar no novo encadeamento.


A maioria dessas respostas perde a visão geral, que é a de que, no que diz respeito à linguagem Java, não há mais diferença entre t.start()e do r.run()que há entre outros dois métodos.

Ambos são apenas métodos. Ambos correm no segmento que os chamou . Ambos fazem o que foram codificados para fazer e, em seguida, retornam, ainda no mesmo segmento, aos seus interlocutores.

A maior diferença é que a maior parte do código para t.start()é código nativo , enquanto, na maioria dos casos, o código para r.run()será Java puro. Mas isso não faz muita diferença. Código é código. O código nativo é mais difícil de encontrar e mais difícil de entender quando você o encontra, mas ainda é apenas o código que informa ao computador o que fazer.

Então o que t.start()faz?

Ele cria um novo encadeamento nativo, organiza a chamada desse encadeamento t.run()e, em seguida, diz ao sistema operacional para permitir que o novo encadeamento seja executado. Então ele retorna.

E o que r.run()faz?

O engraçado é que a pessoa que faz essa pergunta é a pessoa que a escreveu . r.run()faz o que você (ou seja, o desenvolvedor que o escreveu) o projetou para fazer.

Salomão Lento
fonte
4

Thread.start()O código registra o Thread com o planejador e o planejador chama o run()método Além disso, Threadé class enquanto Runnableé uma interface.

CHANDRAHAS
fonte
3

Os pontos que os membros fizeram estão bem, então eu só quero acrescentar algo. O problema é que o JAVA não suporta herança múltipla. Mas o que é se você deseja derivar uma classe B de outra classe A, mas você só pode derivar de uma classe. O problema agora é como "derivar" de ambas as classes: A e Thread. Portanto, você pode usar a interface executável.

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

public class B extends A implements Runnable{...
pommoisel
fonte
bem explicação do método run () com a ajuda de um exemplo sobre Execut�el - uma interface e Tópico - uma classe
mindinho Walve
1

Se você chamar o run()método diretamente , não estará usando o recurso de multiencadeamento, pois o run()método é executado como parte do encadeamento do chamador.

Se você chamar o start()método no Thread, a Java Virtual Machine chamará o método run () e dois threads serão executados simultaneamente - Thread Atual ( main()no seu exemplo) e Outro Thread (Runnable r1no seu exemplo).

Veja o código-fonte do start()método em classe 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();

No código acima, você não pode ver a invocação para o run()método

private native void start0()é responsável por chamar o run()método. A JVM executa esse método nativo.

Ravindra babu
fonte
0

No primeiro caso, você está apenas invocando o run()método do r1er2 objetos .

No segundo caso, você está criando 2 novos Threads!

start()vai ligar run()em algum momento!

Marsellus Wallace
fonte
7
Na verdade, start () não chamará run (): se o fizer, o método run () será executado pelo mesmo encadeamento que chamou start (). O que start () fará é criar um thread que chamará o método run ().
Bruno Reis
0

método run: - é um método abstrato criado originalmente na interface Runnable e substituído na classe Thread, bem como nas subclasses Thread (como o Thread implementa Runnable em seu código-fonte) e em qualquer outra classe de implementação da interface Runnable. - É usado para carregar o encadeamento (objeto executável) com a tarefa que se destina a executar, assim você o substitui para gravar essa tarefa.

método start: - é definido na classe Thread. Quando o método start é chamado em um objeto Thread 1, ele chama o método nativo internamente (não-java) chamado start0 (); método.

start0 (); método: é responsável pelo baixo processamento (criação de pilha para um encadeamento e alocação de encadeamento na fila do processador). Neste ponto, temos um encadeamento no estado Pronto / Executável.

2- No momento em que o agendador de encadeamentos decide que um encadeamento entra no núcleo do processador de acordo com o método de execução (prioridade do encadeamento e algoritmo de agendamento do SO), é invocado no objeto Runnable (seja o objeto de encadeamento Runnable atual ou o objeto Runnable passado) ao construtor de encadeamentos) aqui, um encadeamento entra em um estado de Execução e começa a executar sua tarefa (método de execução)

Esraa Salama
fonte
-2

Os métodos start () e run () separados na classe Thread fornecem duas maneiras de criar programas encadeados. O método start () inicia a execução do novo thread e chama o método run (). O método start () retorna imediatamente e o novo thread normalmente continua até o método run () retornar.

O método run () da classe Thread não faz nada; portanto, as subclasses devem substituir o método pelo código a ser executado no segundo thread. Se um Thread for instanciado com um argumento Runnable, o método run () do thread executará o método run () do objeto Runnable no novo thread.

Dependendo da natureza do seu programa encadeado, chamar o método Thread run () diretamente pode fornecer a mesma saída que chamar pelo método start (), mas, no último caso, o código é realmente executado em um novo encadeamento.

gtzinos
fonte
2
Chamar `run () 'não é uma maneira de criar programas encadeados. Há apenas um caminho.
Marquês de Lorne
-2

A chamada do método Start () executa o método de substituição da classe estendida Thread e da interface dos implementos Runnable.

Mas, chamando run (), procura pelo método run, mas se a classe implementa a interface Runnable, chama o método run () substitui o método Runnable.

ex.:

`

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 ");
    }
}

`

ankit
fonte