Desde que tempo passei com threads em Java, encontrei estas duas maneiras de escrever threads:
Com implements Runnable
:
public class MyRunnable implements Runnable {
public void run() {
//Code
}
}
//Started with a "new Thread(new MyRunnable()).start()" call
Ou, com extends Thread
:
public class MyThread extends Thread {
public MyThread() {
super("MyThread");
}
public void run() {
//Code
}
}
//Started with a "new MyThread().start()" call
Existe alguma diferença significativa nesses dois blocos de código?
java
multithreading
runnable
implements
java-threads
user65374
fonte
fonte
interrupt()
. Novamente, é uma ideia, pode ser útil no caso certo, mas não o recomendo.Respostas:
Sim: implementos
Runnable
é a maneira preferida de fazer isso, IMO. Você não está realmente especializando o comportamento do thread. Você está apenas dando algo para executar. Isso significa que a composição é o caminho filosoficamente "mais puro" a seguir.Em termos práticos , significa que você também pode implementar
Runnable
e estender a partir de outra classe.fonte
if (numberCores > 4) myExecutor.excute(myRunnable); else myRunnable.run()
extends Thread
e se você não quer enfiar por que você iria mesmo implementarRunnable
...tl; dr: implementa Runnable é melhor. No entanto, a ressalva é importante
Em geral, eu recomendaria o uso de algo como,
Runnable
e nãoThread
porque isso permite que você mantenha seu trabalho apenas vagamente associado à sua escolha de simultaneidade. Por exemplo, se você usar aeRunnable
decidir mais tarde que isso não exige sua própria propriedadeThread
, basta chamar threadA.run ().Advertência: Por aqui, desencorajo fortemente o uso de Threads brutos. Eu prefiro o uso de Callables e FutureTasks (do javadoc: "Uma computação assíncrona cancelável"). A integração de tempos limite, o cancelamento adequado e o pool de threads do suporte a simultaneidade moderno são todos muito mais úteis para mim do que pilhas de Threads brutos.
Acompanhamento: existe um
FutureTask
construtor que permite usar o Runnables (se é com isso que você se sente mais confortável) e ainda obter o benefício das modernas ferramentas de concorrência. Para citar o javadoc :Se você não precisar de um resultado específico, considere usar construções do formulário:
Portanto, se substituirmos o deles
runnable
pelo seuthreadA
, obteremos o seguinte:Outra opção que permite que você fique mais perto do Runnables é um ThreadPoolExecutor . Você pode usar o método execute para executar um Runnable para executar "a tarefa especificada em algum momento no futuro".
Se você quiser tentar usar um pool de threads, o fragmento de código acima se tornaria algo como o seguinte (usando o método de fábrica Executors.newCachedThreadPool () ):
fonte
es
seria melhor como um campo estático (ou injetado) para que seja criado apenas uma vez.FutureTask
diretamente com isso geralmente não é o que você deseja fazer.ExecutorService
s irá criar o apropriadoFuture
para você quando vocêsubmit
umRunnable
/Callable
a eles. Da mesma forma para seScheduledExecutorService
eScheduledFuture
quando vocêschedule
aRunnable
/Callable
.Moral da história:
Herdar apenas se você deseja substituir algum comportamento.
Ou melhor, deve ser lido como:
Herdar menos, interagir mais.
fonte
run()
método.java.lang.Thread
substituindo orun()
método Nesse caso, você precisa substituir ostart()
método, eu acho. Normalmente, você apenas reutiliza o comportamento dojava.lang.Thread
injetando seu bloco de execução norun()
método.Bem, tantas boas respostas, quero acrescentar mais sobre isso. Isso ajudará a entender
Extending v/s Implementing Thread
.O Extends vincula dois arquivos de classe muito de perto e pode causar dificuldades para lidar com o código.
Ambas as abordagens fazem o mesmo trabalho, mas houve algumas diferenças.
A diferença mais comum é
Entretanto, uma diferença significativa entre a implementação de Thread Runnable e de extensão é que
by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.
O exemplo a seguir ajudará você a entender mais claramente
Saída do programa acima.
Na abordagem da interface Runnable, apenas uma instância de uma classe está sendo criada e foi compartilhada por diferentes threads. Portanto, o valor do contador é incrementado para cada acesso ao encadeamento.
Considerando que, na abordagem da classe Thread, você deve criar uma instância separada para cada acesso ao thread. Portanto, memória diferente é alocada para todas as instâncias de classe e cada uma possui um contador separado, o valor permanece o mesmo, o que significa que nenhum incremento ocorrerá porque nenhuma referência a objeto é a mesma.
Quando usar o Runnable?
Use a interface Runnable quando desejar acessar os mesmos recursos do grupo de threads. Evite usar a classe Thread aqui, porque a criação de vários objetos consome mais memória e isso se torna uma grande sobrecarga de desempenho.
Uma classe que implementa Runnable não é um thread e apenas uma classe. Para um Runnable se tornar um Thread, você precisa criar uma instância do Thread e passar como o destino.
Na maioria dos casos, a interface Runnable deve ser usada se você planeja substituir o
run()
método e nenhum outro método Thread. Isso é importante porque as classes não devem ser subclassificadas, a menos que o programador pretenda modificar ou aprimorar o comportamento fundamental da classe.Quando é necessário estender uma superclasse, implementar a interface Runnable é mais apropriado do que usar a classe Thread. Porque podemos estender outra classe enquanto implementamos a interface Runnable para criar um thread.
Espero que isso ajude!
fonte
ExtendsThread et = new ExtendsThread();
Thread tc1 = new Thread(et);
tc1.start();
Thread.sleep(1000);
Thread tc2 = new Thread(et);
tc2.start();
Thread.sleep(1000);
Thread tc3 = new Thread(et);
tc3.start();
É mais claro?Thread
aumentando, a declaração estáby extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance
errada? Caso contrário, qual é o caso que demonstra isso?Uma coisa que me surpreende ainda não foi mencionada é que a implementação
Runnable
torna sua classe mais flexível.Se você estender o encadeamento, a ação que você está executando sempre estará em um encadeamento. No entanto, se você implementar
Runnable
, não precisa ser. Você pode executá-lo em um encadeamento, ou passá-lo para algum tipo de serviço executor, ou apenas distribuí-lo como uma tarefa em um único aplicativo encadeado (talvez para ser executado posteriormente, mas dentro do mesmo encadeamento). As opções são muito mais abertas se você apenas usar doRunnable
que se vincularThread
.fonte
Thread
objeto porqueThread implements Runnable
… ;-) Mas "é melhor" fazer essas coisas com a doRunnable
que fazê-las com aThread
!Thread
adiciona muitas coisas extras que você não precisa e, em muitos casos, não deseja. É sempre melhor implementar a interface que corresponde ao que você está realmente fazendo.Se você deseja implementar ou estender qualquer outra classe, a
Runnable
interface é mais preferível; caso contrário, se você não deseja que outra classe estenda ou implemente, aThread
classe é preferível.A diferença mais comum é
Quando você
extends Thread
estuda, depois disso, você não pode estender nenhuma outra classe necessária. (Como você sabe, Java não permite herdar mais de uma classe).Quando você
implements Runnable
pode economizar espaço para sua classe estender qualquer outra classe no futuro ou agora.O Java não suporta várias heranças, o que significa que você só pode estender uma classe em Java; assim, ao estender a classe Thread, você perde a chance e não pode estender ou herdar outra classe em Java.
Na programação orientada a objetos, estender uma classe geralmente significa adicionar novas funcionalidades e modificar ou melhorar comportamentos. Se não estamos fazendo nenhuma modificação no Thread, use a interface Runnable.
A interface executável representa uma tarefa que pode ser executada por Thread ou Executores simples ou por qualquer outro meio. A separação lógica da tarefa como executável que o thread é uma boa decisão de design.
Separar a tarefa como Executável significa que podemos reutilizá-la e também temos a liberdade de executá-la de diferentes maneiras. pois você não pode reiniciar um thread depois que ele for concluído. novamente Runnable vs Thread para tarefa, Runnable é vencedor.
O designer Java reconhece isso e é por isso que os Executores aceitam Runnable como Task e têm um thread de trabalho que executa essas tarefas.
Herdar todos os métodos Thread é uma sobrecarga adicional apenas para representar uma tarefa que pode ser feita facilmente com o Runnable.
Cortesia de javarevisited.blogspot.com
Essas foram algumas das diferenças notáveis entre Thread e Runnable em Java. Se você conhece outras diferenças no Thread vs Runnable, compartilhe-o por meio de comentários. Eu pessoalmente uso o Runnable over Thread para esse cenário e recomenda o uso da interface Runnable ou Callable com base nos seus requisitos.
No entanto, a diferença significativa é.
Quando você
extends Thread
classifica, cada segmento cria um objeto exclusivo e se associa a ele. Quando vocêimplements Runnable
compartilha o mesmo objeto em vários segmentos.fonte
Na verdade, não é sábio para comparar
Runnable
eThread
uns com os outros.Esses dois têm uma dependência e um relacionamento no multi-threading, assim como o
Wheel and Engine
relacionamento do veículo a motor.Eu diria que há apenas uma maneira de multi-threading com duas etapas. Deixe-me fazer o meu ponto.
Executável:
ao implementar
interface Runnable
, significa que você está criando algo que estárun able
em um thread diferente. Agora, criar algo que possa ser executado dentro de um thread (executável dentro de um thread) não significa criar um Thread.Portanto, a classe
MyRunnable
nada mais é do que uma classe comum com umvoid run
método. E seus objetos serão alguns objetos comuns, com apenas um métodorun
que será executado normalmente quando chamado. (a menos que passemos o objeto em um thread).Thread:,
class Thread
eu diria Uma classe muito especial com a capacidade de iniciar um novo Thread que, na verdade, permite multi-threading através de seustart()
método.Por que não é sábio comparar?
Porque precisamos de ambos para multiencadeamento.
Para Multi-threading, precisamos de duas coisas:
Então, técnica e teoricamente, os dois são necessários para iniciar um segmento, um será executado e o outro será executado (como
Wheel and Engine
no veículo a motor).É por isso que você não pode iniciar um encadeamento com
MyRunnable
você precisa passá-lo para uma instância deThread
.Mas é possível criar e executar um encadeamento usando apenas
class Thread
porque o ClassThread
implementa,Runnable
assim todos sabemos queThread
também éRunnable
interno.Finalmente
Thread
eRunnable
são complementares entre si para multithreading não concorrente ou substituição.fonte
ThreadA
não tem mais sentidoVocê deve implementar o Runnable, mas se estiver executando no Java 5 ou superior, não deve iniciá-lo,
new Thread
mas usar um ExecutorService . Para obter detalhes, consulte: Como implementar threading simples em Java .fonte
Não sou especialista, mas posso pensar em um motivo para implementar Runnable em vez de estender Thread: Java suporta apenas herança única, portanto, você pode estender apenas uma classe.
Edit: Originalmente dito "A implementação de uma interface requer menos recursos". também, mas você precisa criar uma nova instância do Thread de qualquer maneira, então isso estava errado.
fonte
Eu diria que existe uma terceira maneira:
Talvez isso tenha sido influenciado um pouco pelo meu recente uso pesado de Javascript e Actionscript 3, mas dessa forma sua classe não precisa implementar uma interface bastante vaga como essa
Runnable
.fonte
Com o lançamento do Java 8, agora existe uma terceira opção.
Runnable
é uma interface funcional , o que significa que instâncias dela podem ser criadas com expressões lambda ou referências de método.Seu exemplo pode ser substituído por:
ou se você deseja usar uma
ExecutorService
e uma referência de método:Estes não são apenas muito mais curtos que os seus exemplos, mas também trazem muitas das vantagens indicadas em outras respostas do uso
Runnable
excessivoThread
, como responsabilidade única e uso da composição, porque você não está especializando o comportamento do encadeamento. Dessa maneira, também evita-se a criação de uma classe extra, se tudo o que você precisa é oRunnable
que você faz em seus exemplos.fonte
() -> {}
é suposto representar a lógica personalizada de que alguém precisa? Então seria melhor dizer como() -> { /* Code here */ }
?A instanciação de uma interface oferece uma separação mais limpa entre seu código e a implementação de threads, portanto, eu preferiria implementar o Runnable nesse caso.
fonte
Todos aqui parecem pensar que implementar o Runnable é o caminho a percorrer e eu realmente não discordo deles, mas também há um motivo para estender o Thread na minha opinião, na verdade, você meio que demonstrou isso no seu código.
Se você implementar Runnable, a classe que implementa Runnable não tem controle sobre o nome do encadeamento, é o código de chamada que pode definir o nome do encadeamento, assim:
mas se você estender o Thread, poderá gerenciar isso dentro da própria classe (assim como no seu exemplo, você nomeará o segmento 'ThreadB'). Nesse caso, você:
A) pode dar a ele um nome mais útil para fins de depuração
B) estão forçando que esse nome seja usado para todas as instâncias dessa classe (a menos que você ignore o fato de que é um encadeamento e faça o acima com ele como se fosse um Runnable, mas estamos falando de convenção aqui em qualquer caso, portanto, pode ignore essa possibilidade que sinto).
Você pode, por exemplo, pegar um rastreio de pilha de sua criação e usá-lo como o nome do encadeamento. Isso pode parecer estranho, mas dependendo da estrutura do seu código, pode ser muito útil para fins de depuração.
Isso pode parecer uma coisa pequena, mas onde você tem um aplicativo muito complexo com muitos threads e de repente coisas "pararam" (por razões de conflito ou possivelmente por causa de uma falha em um protocolo de rede, seria menos óbvio - ou por outras razões sem fim), obter um despejo de pilha do Java, onde todos os threads são chamados 'Thread-1', 'Thread-2', 'Thread-3' nem sempre é muito útil (depende de como seus threads são estruturado e se é útil saber qual é qual apenas pelo rastreamento da pilha - nem sempre é possível se você estiver usando grupos de vários threads executando o mesmo código).
Dito isto, é claro que você também pode fazer o acima de uma maneira genérica, criando uma extensão da classe thread que define seu nome para um rastreamento de pilha de sua chamada de criação e, em seguida, use isso com suas implementações Runnable em vez da classe Thread Java padrão (veja abaixo), mas, além do rastreamento da pilha, pode haver mais informações específicas do contexto que seriam úteis no nome do encadeamento para depuração (uma referência a uma das muitas filas ou soquetes que ele poderia processar, por exemplo, caso em que você prefere estenda o Thread especificamente para esse caso, para que o compilador force você (ou outras pessoas usando suas bibliotecas) a transmitir determinadas informações (por exemplo, a fila / soquete em questão) para uso no nome).
Aqui está um exemplo do encadeamento genérico com o rastreamento da pilha de chamada como seu nome:
e aqui está uma amostra da saída comparando os dois nomes:
fonte
Runnable
pode realmente controlar o nome do encadeamento, pois o encadeamento que executa o código é, por definição, o encadeamento atual (e qualquer código que passa nas verificações de segurança tem controle sobre os nomes dos encadeamentos). Considerando que você dedica metade do seu post para "omg, e quanto aos nomes de tópicos!", Isso parece um grande negócio.Executável porque:
Mesmo se você não precisar de nada disso agora, poderá no futuro. Como não há benefício em substituir o Thread, o Runnable é uma solução melhor.
fonte
Como esse é um tópico muito popular e as boas respostas estão espalhadas por toda parte e tratadas com grande profundidade, achei justificável compilar as boas respostas dos outros em uma forma mais concisa, para que os novatos tenham uma visão geral fácil:
Você geralmente estende uma classe para adicionar ou modificar a funcionalidade. Então, se você não quer para substituir qualquer comportamento da linha , em seguida, usar Runnable.
Da mesma forma, se você não precisar herdar métodos de encadeamento, poderá passar sem essa sobrecarga usando Runnable.
Herança única : se você estender o Thread, não poderá estender a partir de nenhuma outra classe; portanto, se é isso que você precisa fazer, use o Runnable.
É um bom design separar a lógica do domínio dos meios técnicos; nesse sentido, é melhor ter uma tarefa Runnable isolando sua tarefa do seu runner .
Você pode executar o mesmo objeto Runnable várias vezes ; um objeto Thread, no entanto, só pode ser iniciado uma vez. (Talvez o motivo pelo qual os Executores aceitem Runnables, mas não os Threads.)
Se você desenvolver sua tarefa como executável, terá toda a flexibilidade de como usá-la agora e no futuro . Você pode executá-lo simultaneamente via Executors, mas também via Thread. E você ainda pode usar / chamá-lo de forma não simultânea no mesmo encadeamento, assim como qualquer outro tipo / objeto comum.
Isso também facilita a separação de aspectos de lógica de tarefa e simultaneidade em seus testes de unidade .
Se você está interessado nesta pergunta, também pode estar interessado na diferença entre Chamada e Runnable .
fonte
As diferenças entre Estender Thread e Implementar Runnable são:
fonte
Isso é discutido no tutorial Definindo e iniciando um encadeamento da Oracle :
Em outras palavras, a implementação
Runnable
funcionará em cenários em que sua classe estende uma classe diferente deThread
. Java não suporta herança múltipla. Além disso, a extensãoThread
não será possível ao usar algumas das APIs de gerenciamento de encadeamento de alto nível. O único cenário em que a extensãoThread
é preferível é em um aplicativo pequeno que não estará sujeito a atualizações no futuro. Quase sempre é melhor implementarRunnable
lo, pois é mais flexível à medida que seu projeto cresce. Uma mudança de design não terá um grande impacto, pois você pode implementar muitas interfaces em java, mas apenas estender uma classe.fonte
A explicação mais simples seria implementando:
Runnable
podemos atribuir o mesmo objeto a vários threads e cadaThread
compartilha os mesmos estados e comportamento do objeto.Por exemplo, suponha que haja dois encadeamentos, o encadeamento1 coloca um número inteiro em uma matriz e o encadeamento2 pega números inteiros da matriz quando a matriz é preenchida. Observe que, para que o thread2 funcione, ele precisa conhecer o estado da matriz, se o thread1 o preencheu ou não.
A implementação
Runnable
permite que você tenha essa flexibilidade para compartilhar o objeto, enquantoextends Thread
faz com que você crie novos objetos para cada encadeamento, portanto, qualquer atualização feita pelo encadeamento1 é perdida no encadeamento2.fonte
Se não estou errado, é mais ou menos parecido com
Qual é a diferença entre uma interface e uma classe abstrata?
estende estabelece relação " É um " e interface fornece capacidade " Tem um ".
Prefere implementa Runnable :
Prefere " estende o segmento ":
Geralmente, você não precisa substituir o comportamento do Thread. Então implementa Runnable é o preferido na maioria das vezes.
Em uma observação diferente, o uso de API avançada
ExecutorService
ouThreadPoolExecutorService
fornece mais flexibilidade e controle.Dê uma olhada nesta pergunta SE:
ExecutorService vs Casual Thread Spawner
fonte
A separação da classe Thread da implementação Runnable também evita possíveis problemas de sincronização entre o thread e o método run (). Um Runnable separado geralmente oferece maior flexibilidade na maneira como o código executável é referenciado e executado.
fonte
Esse é o S do SOLID : responsabilidade única.
Um encadeamento incorpora o contexto de execução (como no contexto de execução: quadro de pilha, ID de encadeamento, etc.) da execução assíncrona de um trecho de código. Idealmente, esse trecho de código deve ter a mesma implementação, síncrona ou assíncrona .
Se os agrupar em uma implementação, você fornecerá ao objeto resultante duas causas de mudança não relacionadas :
Se o idioma que você usa suportar classes parciais ou herança múltipla, você poderá segregar cada causa em sua própria superclasse, mas tudo se resume a compor os dois objetos, já que seus conjuntos de recursos não se sobrepõem. Isso é para a teoria.
Na prática, de um modo geral, um programa não precisa ter mais complexidade do que o necessário. Se você tem um encadeamento trabalhando em uma tarefa específica, sem nunca alterá-la, provavelmente não faz sentido separar as tarefas de classes e seu código permanece mais simples.
No contexto de Java , como o recurso já está lá , é provavelmente mais fácil iniciar diretamente com
Runnable
classes independentes e transmitir suas instâncias paraThread
(ouExecutor
) instâncias. Uma vez acostumado a esse padrão, não é mais difícil de usar (ou mesmo ler) do que o simples caso de thread executável.fonte
Um motivo pelo qual você deseja implementar uma interface em vez de estender uma classe base é que você já está estendendo alguma outra classe. Você pode estender apenas uma classe, mas pode implementar qualquer número de interfaces.
Se você estender o Thread, estará basicamente impedindo que sua lógica seja executada por qualquer outro thread que não seja 'this'. Se você deseja que apenas um thread execute sua lógica, é melhor implementar o Runnable.
fonte
se você usa runnable, pode economizar espaço para estender a qualquer outra classe.
fonte
Podemos voltar a visitar a razão básica pela qual queríamos que nossa classe se comportasse como
Thread
? Não há motivo algum, apenas queríamos executar uma tarefa, provavelmente em modo assíncrono, o que significa precisamente que a execução da tarefa deve se ramificar de nosso encadeamento principal e do encadeamento principal se terminar cedo, pode ou não esperar para o caminho ramificado (tarefa).Se esse for o objetivo, onde vejo a necessidade de um Thread especializado. Isso pode ser conseguido escolhendo um Thread RAW no Pool de Threads do sistema e atribuindo a ele nossa tarefa (pode ser uma instância da nossa classe) e é isso.
Então, vamos obedecer ao conceito de POO e escrever uma classe do tipo que precisamos. Existem muitas maneiras de fazer as coisas, da maneira certa.
Como precisamos de uma tarefa, escreva uma definição de tarefa que possa ser executada em um Thread. Então use Runnable.
Lembre-se sempre de que
implements
é especialmente usado para transmitir um comportamento eextends
é usado para transmitir um recurso / propriedade.Não queremos a propriedade do encadeamento, mas queremos que nossa classe se comporte como uma tarefa que pode ser executada.
fonte
Sim, se você chamar a chamada ThreadA, não precisará chamar o método start e o método run é chamar após chamada apenas a classe ThreadA. Mas se usar a chamada ThreadB, será necessário o thread inicial para o método de execução de chamada. Se você tiver mais alguma ajuda, me responda.
fonte
Acho que é mais útil usar o Runnable por todos os motivos mencionados, mas às vezes gosto de estender o Thread para que eu possa criar meu próprio método de parada de thread e chamá-lo diretamente no thread que eu criei.
fonte
Java não suporta herança múltipla, portanto, se você estender a classe Thread, nenhuma outra classe será estendida.
Por exemplo: Se você criar um applet, ele deverá estender a classe Applet; portanto, aqui a única maneira de criar encadeamento é implementando a interface Runnable
fonte
Runnable
é uma interface, enquantoThread
é uma classe que implementa essa interface. Do ponto de vista do design, deve haver uma separação clara entre como uma tarefa é definida e entre como é executada. O primeiro é de responsabilidade de umaRunnalbe
implementação e o segundo é o trabalho daThread
classe. Na maioria dos casos, implementarRunnable
é o caminho certo a seguir.fonte
Diferença entre Thread e executável. Se estamos criando Thread usando a classe Thread, então Number of thread é igual ao número de objeto que criamos. Se estivermos criando um encadeamento implementando a interface executável, podemos usar um único objeto para criar vários encadeamentos.
Portanto, dependendo do requisito, se nossos dados não forem sensíveis. Portanto, pode ser compartilhado entre vários threads, podemos usar a interface Runnable.
fonte
Adicionando meus dois centavos aqui - sempre que possível
implements Runnable
. Abaixo estão duas advertências sobre por que você não deve usarextends Thread
sIdealmente, você nunca deve estender a classe Thread; a
Thread
aula deve ser feitafinal
. Pelo menos seus métodos gostamthread.getId()
. Consulte esta discussão para obter um bug relacionado à extensão deThread
s.Quem gosta de resolver quebra-cabeças pode ver outro efeito colateral da extensão do Thread. O código abaixo imprimirá código inacessível quando ninguém os estiver notificando.
Por favor, consulte http://pastebin.com/BjKNNs2G .
fonte