Como chamar um método com um thread separado em Java?

126

digamos que eu tenho um método doWork(). Como eu o chamo de um thread separado (não do thread principal).

Louis Rhys
fonte
Acontece que existem alguns exemplos mais sobre esta recente questão relacionada: matar um loop infinito em java
Greg Hewgill
stackoverflow.com/questions/36832094/... Eu tenho um problema semelhante pls me ajudar a resolver isso
Sruthi Acg
Você também pode gostar de dar uma olhada no blog sobre Java Reativo.danlew.net/2014/09/09/15/grokking-rxjava-part-1 para tarefas assíncronas #
Nathan Dunn

Respostas:

138

Crie uma classe que implemente a Runnableinterface. Coloque o código que você deseja executar no run()método - esse é o método que você deve escrever para estar em conformidade com a Runnableinterface. No seu segmento "principal", crie uma nova Threadclasse, passando ao construtor uma instância do seu e Runnable, em seguida, chame start()-o. startdiz à JVM para fazer a mágica para criar um novo encadeamento e, em seguida, chame seu runmétodo nesse novo encadeamento.

public class MyRunnable implements Runnable {

    private int var;

    public MyRunnable(int var) {
        this.var = var;
    }

    public void run() {
        // code in the other thread, can reference "var" variable
    }
}

public class MainThreadClass {
    public static void main(String args[]) {
        MyRunnable myRunnable = new MyRunnable(10);
        Thread t = new Thread(myRunnable)
        t.start();
    }    
}

Dê uma olhada no tutorial de simultaneidade do Java para começar.

Se seu método for chamado com frequência, pode não valer a pena criar um novo encadeamento a cada vez, pois essa é uma operação cara. Provavelmente seria melhor usar algum tipo de pool de threads. Ter um olhar para Future, Callable, Executorclasses no java.util.concurrentpacote.

Noel M
fonte
1
e se houver uma variável que você gostaria de passar?
Louis Rhys
8
O run()método não usa parâmetros, portanto você não pode passar uma variável para lá. Sugiro que você o passe no construtor - editarei minha resposta para mostrar isso.
Noel M
1
Existe uma maneira curta de chamar um método em um thread diferente? Eu sei do new Thread() { public void run() {myMethod();}}.start();caminho, é o mais curto?
9788 Steven Roose
@NoelM, você pode explicar a diferença entre a sua e a resposta da MANN?
Asif Mushtaq
2
A resposta de MANN usa uma implementação anônima de Runnable- mine é uma classe que se estende Runnable. E porque fiz isso, tenho meu próprio construtor, que passa o estado para o objeto instanciado.
Noel M
183
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        // code goes here.
    }
});  
t1.start();

ou

new Thread(new Runnable() {
     @Override
     public void run() {
          // code goes here.
     }
}).start();

ou

new Thread(() -> {
    // code goes here.
}).start();

ou

Executors.newSingleThreadExecutor().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});

ou

Executors.newCachedThreadPool().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});
MANN
fonte
Isso funcionou perfeitamente para o que eu estava fazendo. Necessário executar um serviço da web e atualizar uma barra de progresso simultaneamente usando o padrão de observador.
dpi
@ Ashish: Por favor, explique o que e por que foi editado?
MANN 30/10
1
@AshishAggarwal: Parece estranho para mim quando alguém faz isso sem ter permissão do autor!
MANN
@MANN, você pode explicar por que usa o método run no parâmetro Thread? melhor desempenho?
Asif Mushtaq
1
Precisamos terminar explicitamente o encadeamento? Não existe o risco de criar um vazamento de memória ao encerrar explicitamente o encadeamento? Ou o segmento termina quando termina run()?
theyuv
59

No Java 8, você pode fazer isso com uma linha de código.

Se o seu método não usar nenhum parâmetro, você poderá usar uma referência de método:

new Thread(MyClass::doWork).start();

Caso contrário, você pode chamar o método em uma expressão lambda:

new Thread(() -> doWork(someParam)).start();
Aaron Cohn
fonte
Desculpe trazer isso de volta, mas o que exatamente ->significa?
Kyle
1
Essa é a sintaxe usada para criar uma expressão lambda. Dê uma olhada nestes links para obter mais informações: O que '->' faz em Java? e The Java ™ Tutorials - Expressões lambda
Aaron Cohn
@AaronCohn great stuff man! Você conhece alguma alternativa para threads em Java? Eu venho do mundo Python, whre usaríamos Celery task queuepara para o material assíncrono
CESCO
O Java tem abstrações de nível superior para lidar com Threads , mas talvez você esteja procurando algo mais como o Akka ?
Aaron Cohn
8

Outra opção mais rápida de chamar coisas (como DialogBoxes e MessageBoxes e criar threads separados para métodos seguros não relacionados a threads) seria usar a expressão Lamba

  new Thread(() -> {
                      "code here"
            }).start();
Rohan Sawant
fonte
3

Algum tempo atrás, eu escrevi uma classe de utilitário simples que usa o serviço executor JDK5 e executa processos específicos em segundo plano. Como doWork () normalmente teria um valor de retorno nulo, convém usar essa classe de utilitário para executá-lo em segundo plano.

Veja este artigo onde eu havia documentado esse utilitário.

raja kolluru
fonte
6
Futuro e Callable fazem esse tipo de coisa para você.
Amir Afghani
Sim eles fazem. a idéia aqui é abstrair a interface atrás de um wrapper assíncrono.
raja kolluru
O link está quebrado (404).
palacsint
3

Para conseguir isso com o RxJava 2.x, você pode usar:

Completable.fromAction(this::dowork).subscribeOn(Schedulers.io().subscribe();

O subscribeOn()método especifica em qual agendador executar a ação - o RxJava possui vários agendadores predefinidos, incluindo Schedulers.io()um conjunto de encadeamentos destinado a operações de E / S e Schedulers.computation()qual é destinado a operações intensivas da CPU.

Clyde
fonte
3

Se você estiver usando pelo menos Java 8, poderá usar o método runAsyncda classe CompletableFuture

CompletableFuture.runAsync(() -> {...});

Se você precisa retornar um resultado use supplyAsyncvez

CompletableFuture.supplyAsync(() -> 1);
k13i
fonte