Wie rufe ich eine Methode mit einem separaten Thread in Java auf?

126

Nehmen wir an, ich habe eine Methode doWork(). Wie rufe ich es von einem separaten Thread auf (nicht vom Haupt-Thread)?

Louis Rhys
quelle
Es gibt einige Beispiele zu dieser kürzlich verwandten Frage: Töten einer Endlosschleife in Java
Greg Hewgill
stackoverflow.com/questions/36832094/… Ich habe ein ähnliches Problem. Bitte helfen Sie mir, dieses
Problem
Sie können auch einen Blick auf Reactive Java blog.danlew.net/2014/09/15/grokking-rxjava-part-1 für asynchrone Aufgaben werfen
Nathan Dunn

Antworten:

138

Erstellen Sie eine Klasse, die die RunnableSchnittstelle implementiert . Fügen Sie den Code, den Sie ausführen möchten, in die run()Methode ein - das ist die Methode, die Sie schreiben müssen, um der RunnableSchnittstelle zu entsprechen . Erstellen Sie in Ihrem "Haupt" -Thread eine neue ThreadKlasse, übergeben Sie dem Konstruktor eine Instanz von Ihnen Runnableund rufen Sie start()sie dann auf. startWeist die JVM an, die Magie auszuführen, um einen neuen Thread zu erstellen, und dann Ihre runMethode in diesem neuen Thread aufzurufen .

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

Schauen Sie sich das Parallelitäts-Tutorial von Java an, um loszulegen.

Wenn Ihre Methode häufig aufgerufen wird, lohnt es sich möglicherweise nicht, jedes Mal einen neuen Thread zu erstellen, da dies eine teure Operation ist. Es wäre wahrscheinlich am besten, einen Thread-Pool zu verwenden. Werfen Sie einen Blick auf Future, Callable, ExecutorKlassen im java.util.concurrentPaket.

Noel M.
quelle
1
Was ist, wenn es eine Variable gibt, die Sie übergeben möchten?
Louis Rhys
8
Die run()Methode akzeptiert keine Parameter, daher können Sie dort keine Variable übergeben. Ich würde vorschlagen, dass Sie es im Konstruktor übergeben - ich werde meine Antwort bearbeiten, um das zu zeigen.
Noel M
1
Gibt es eine kurze Möglichkeit, eine Methode in einem anderen Thread aufzurufen? Ich weiß von dem new Thread() { public void run() {myMethod();}}.start();Weg, ist das der kürzeste?
Steven Roose
@NoelM Kannst du den Unterschied zwischen deiner und der Antwort von MANN erklären?
Asif Mushtaq
2
Die Antwort von MANN verwendet eine anonyme Implementierung von Runnable- meine ist eine Klasse, die erweitert wird Runnable. Und weil ich das getan habe, habe ich meinen eigenen Konstruktor, der den Zustand an das instanziierte Objekt übergibt.
Noel M
182
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        // code goes here.
    }
});  
t1.start();

oder

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

oder

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

oder

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

oder

Executors.newCachedThreadPool().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});
MANN
quelle
Das funktionierte perfekt für das, was ich tat. Erforderlich, um einen Webservice auszuführen und einen Fortschrittsbalken gleichzeitig mithilfe des Beobachtermusters zu aktualisieren.
dpi
@Ashish: Bitte erklären Sie, was und warum bearbeitet wurde?
MANN
1
@AshishAggarwal: Sieht komisch aus, wenn jemand das tut, ohne die Erlaubnis des Autors einzuholen!
MANN
@MANN können Sie erklären, warum Sie die Run-Methode im Thread-Parameter verwenden? eine bessere Leistung?
Asif Mushtaq
1
Müssen wir den Thread explizit beenden? Besteht nicht die Gefahr eines Speicherverlusts, wenn der Thread nicht explizit beendet wird? Oder wird der Thread beendet, wenn er fertig ist run()?
Theyuv
59

In Java 8 können Sie dies mit einer Codezeile tun.

Wenn Ihre Methode keine Parameter akzeptiert, können Sie eine Methodenreferenz verwenden:

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

Andernfalls können Sie die Methode in einem Lambda-Ausdruck aufrufen:

new Thread(() -> doWork(someParam)).start();
Aaron Cohn
quelle
Es tut mir leid, das zurückzubringen, aber was genau bedeutet das ->?
Kyle
1
Dies ist die Syntax, mit der ein Lambda-Ausdruck erstellt wird. Weitere Informationen finden Sie unter diesen Links: Was macht '->' in Java? und die Java ™ Tutorials - Lambda Expressions
Aaron Cohn
@ AaronCohn tolles Zeug Mann! Kennen Sie Alternativen zu Threads in Java? Ich komme aus der Python-Welt, für die wir Celery task queueasynchrone Dinge verwenden würden
CESCO
Java hat Abstraktionen auf höherer Ebene für den Umgang mit Threads , aber vielleicht suchen Sie etwas mehr wie Akka ?
Aaron Cohn
8

Eine andere schnellere Option zum Aufrufen von Dingen (wie DialogBoxen und MessageBoxen und Erstellen separater Threads für nicht threadsichere Methoden) wäre die Verwendung des Lamba-Ausdrucks

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

Vor einiger Zeit hatte ich eine einfache Dienstprogrammklasse geschrieben, die den JDK5-Executor-Service verwendet und bestimmte Prozesse im Hintergrund ausführt. Da doWork () normalerweise einen ungültigen Rückgabewert hat, möchten Sie diese Dienstprogrammklasse möglicherweise verwenden, um sie im Hintergrund auszuführen.

Siehe diesen Artikel, in dem ich dieses Dienstprogramm dokumentiert hatte.

Raja Kolluru
quelle
6
Future und Callable erledigen so etwas für Sie.
Amir Afghani
Ja, das tun sie. Die Idee hier ist, die Schnittstelle hinter einem asynchronen Wrapper zu abstrahieren.
Raja Kolluru
Die Verbindung ist unterbrochen (404).
Palacsint
3

Um dies mit RxJava 2.x zu erreichen, können Sie Folgendes verwenden:

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

Die subscribeOn()Methode gibt an, auf welchem ​​Scheduler die Aktion ausgeführt werden soll. RxJava verfügt über mehrere vordefinierte Scheduler, darunter Schedulers.io()einen Thread-Pool für E / A-Vorgänge und Schedulers.computation()einen für CPU-intensive Vorgänge.

Clyde
quelle
3

Wenn Sie mindestens Java 8 verwenden, können Sie eine Methode runAsyncaus der Klasse CompletableFuture verwenden

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

Wenn Sie ein Ergebnis zurückgeben müssen, verwenden Sie supplyAsyncstattdessen

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