¿Cómo llamar a un método con un hilo separado en Java?

126

Digamos que tengo un método doWork(). ¿Cómo lo llamo desde un hilo separado (no el hilo principal)?

Louis Rhys
fuente
Resulta que hay algunos ejemplos sobre esta reciente pregunta relacionada: matar un bucle infinito en Java
Greg Hewgill
stackoverflow.com/questions/36832094/… Tengo un problema similar, por favor ayúdame a resolver esto
Sruthi Acg
También puede consultar el blog Reactive Java.danlew.net/2014/09/15/grokking-rxjava-part-1 para tareas asincrónicas
Nathan Dunn

Respuestas:

138

Cree una clase que implemente la Runnableinterfaz. Coloque el código que desea ejecutar en el run()método; ese es el método que debe escribir para cumplir con la Runnableinterfaz. En su hilo "principal", cree una nueva Threadclase, pasando al constructor una instancia de su Runnable, luego invoque start(). startle dice a la JVM que haga la magia para crear un nuevo hilo, y luego llame a su runmétodo en ese nuevo hilo.

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

Eche un vistazo al tutorial de concurrencia de Java para comenzar.

Si su método se va a llamar con frecuencia, entonces puede que no valga la pena crear un nuevo hilo cada vez, ya que esta es una operación costosa. Probablemente sería mejor usar un grupo de subprocesos de algún tipo. Echar un vistazo a Future, Callable, Executorclases en el java.util.concurrentpaquete.

Noel M
fuente
1
¿Qué pasa si hay una variable que le gustaría pasar?
Louis Rhys
8
El run()método no toma parámetros, por lo que no puede pasar una variable allí. Te sugiero que lo pases en el constructor. Editaré mi respuesta para mostrar eso.
Noel M
1
¿Hay alguna forma corta de llamar a 1 método en un hilo diferente? Sé del new Thread() { public void run() {myMethod();}}.start();camino, ¿es el más corto?
Steven Roose
@NoelM, ¿puedes explicar la diferencia entre la tuya y la respuesta de MANN?
Asif Mushtaq
2
La respuesta de MANN utiliza una implementación anónima de Runnable: la mía es una clase que se extiende Runnable. Y como he hecho eso, tengo mi propio constructor que pasa el estado al objeto instanciado.
Noel M
183
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        // code goes here.
    }
});  
t1.start();

o

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

o

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

o

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

o

Executors.newCachedThreadPool().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});
MANN
fuente
Esto funcionó perfectamente para lo que estaba haciendo. Necesario para ejecutar un servicio web y actualizar una barra de progreso simultáneamente usando el patrón de observador.
dpi
@Ashish: ¿Explica qué y por qué se ha editado?
MANN
1
@AshishAggarwal: ¡Me parece extraño cuando alguien hace eso sin pedir permiso al autor!
MANN
@MANN, ¿puede explicar por qué utiliza el método de ejecución en el parámetro Thread? cualquier mejor rendimiento?
Asif Mushtaq
1
¿Necesitamos terminar explícitamente el hilo? ¿No existe el riesgo de crear una pérdida de memoria al no terminar explícitamente el hilo? ¿O el hilo termina cuando termina run()?
Theyuv
59

En Java 8 puede hacer esto con una línea de código.

Si su método no toma ningún parámetro, puede usar una referencia de método:

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

De lo contrario, puede llamar al método en una expresión lambda:

new Thread(() -> doWork(someParam)).start();
Aaron Cohn
fuente
lamento traer esto de vuelta, pero ¿qué significa exactamente ->?
Kyle
1
Esa es la sintaxis utilizada para crear una expresión lambda. Eche un vistazo a estos enlaces para obtener más información: ¿Qué hace '->' en Java? y The Java ™ Tutorials - Expresiones de Lambda
Aaron Cohn
@AaronCohn cosas geniales hombre! ¿Conoces alguna alternativa a los hilos en Java? Vengo del mundo de Python, donde los Celery task queue
usaríamos
Java tiene abstracciones de mayor nivel para lidiar con subprocesos , pero ¿tal vez estás buscando algo más como Akka ?
Aaron Cohn el
8

Otra opción más rápida para llamar a cosas (como DialogBoxes y MessageBoxes y crear subprocesos separados para métodos que no sean seguros para subprocesos) sería usar Lamba Expression

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

Hace algún tiempo, había escrito una clase de utilidad simple que usa el servicio de ejecución JDK5 y ejecuta procesos específicos en segundo plano. Como doWork () normalmente tendría un valor de retorno nulo, es posible que desee utilizar esta clase de utilidad para ejecutarla en segundo plano.

Vea este artículo donde había documentado esta utilidad.

raja kolluru
fuente
66
Future y Callable hacen este tipo de cosas por ti.
Amir Afghani
Sí lo hacen. La idea aquí es abstraer la interfaz detrás de un contenedor asíncrono.
raja kolluru
El enlace está roto (404).
palacsint
3

Para lograr esto con RxJava 2.x puede usar:

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

El subscribeOn()método especifica en qué planificador ejecutar la acción: RxJava tiene varios planificadores predefinidos, incluido el Schedulers.io()que tiene un grupo de subprocesos destinado a operaciones de E / S y el Schedulers.computation()que está destinado a operaciones intensivas de CPU.

Clyde
fuente
3

Si está utilizando al menos Java 8, puede usar el método runAsyncde la clase CompletableFuture

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

Si necesita devolver un resultado, use supplyAsyncen su lugar

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