Jak wywołać metodę z osobnym wątkiem w Javie?


Odpowiedzi:


138

Utwórz klasę, która implementuje Runnableinterfejs. Umieść kod, który chcesz uruchomić w run()metodzie - to metoda, którą musisz napisać, aby była zgodna z Runnableinterfejsem. W swoim "głównym" wątku utwórz nową Threadklasę, przekazując konstruktorowi twoją instancję Runnable, a następnie wywołaj start()ją. startmówi JVM, aby wykonał magię, aby utworzyć nowy wątek, a następnie wywołać runmetodę w tym nowym wątku.

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

Spójrz na samouczku współbieżności Java , aby zacząć.

Jeśli twoja metoda będzie często wywoływana, może nie być warto tworzyć za każdym razem nowego wątku, ponieważ jest to kosztowna operacja. Prawdopodobnie najlepiej byłoby użyć jakiejś puli wątków. Przyjrzeć się Future, Callable, Executorklas w java.util.concurrentpakiecie.


1
co jeśli jest zmienna, którą chciałbyś przekazać?
Louis Rhys

8
run()Metoda bierze żadnych parametrów, więc nie można przekazać nie zmienną. Proponuję przekazać to w konstruktorze - edytuję swoją odpowiedź, aby to pokazać.
Noel M

1
Czy istnieje krótki sposób wywołania metody 1 w innym wątku? Znam new Thread() { public void run() {myMethod();}}.start();drogę, czy to najkrótsza?
Steven Roose

@NoelM czy możesz wyjaśnić różnicę między odpowiedzią twoją a odpowiedzią MANN?
Asif Mushtaq

2
Odpowiedź MANN wykorzystuje anonimową implementację Runnable- moja to klasa, która rozszerza Runnable. A ponieważ już to zrobiłem, mam swój własny konstruktor, który przekazuje stan do instancji obiektu.
Noel M

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

lub

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

lub

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

lub

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

lub

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

To działało idealnie w tym, co robiłem. Potrzebne do jednoczesnego uruchomienia usługi sieciowej i aktualizacji paska postępu przy użyciu wzorca obserwatora.
dpi

@Ashish: Proszę wyjaśnić, co i dlaczego zostało zmienione?
MANN

1
@AshishAggarwal: Wygląda dziwnie, gdy ktoś robi to bez pozwolenia autora!
MANN

@MANN Czy możesz wyjaśnić, dlaczego używasz metody run w parametrze Thread? jakieś lepsze wyniki?
Asif Mushtaq

1
Czy musimy jawnie zakończyć wątek? Czy nie istnieje ryzyko powstania wycieku pamięci przez niejawne zakończenie wątku? A może wątek kończy się po zakończeniu run()?
theyuv

59

W Javie 8 możesz to zrobić za pomocą jednej linii kodu.

Jeśli Twoja metoda nie przyjmuje żadnych parametrów, możesz użyć odwołania do metody:

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

W przeciwnym razie możesz wywołać metodę w wyrażeniu lambda:

new Thread(() -> doWork(someParam)).start();

przepraszam, że przywracam to, ale co to właściwie ->oznacza?
Kyle

1
To jest składnia używana do tworzenia wyrażenia lambda. Spójrz na te linki, aby uzyskać więcej informacji: Co robi „->” w Javie? oraz Samouczki Java ™ - Wyrażenia lambda
Aaron Cohn,

@AaronCohn świetne rzeczy człowieku! Czy znasz jakieś alternatywy dla wątków w Javie? Pochodzę ze świata Pythona, którego używalibyśmy Celery task queuedo rzeczy asynchronicznych
CESCO

Java ma wyższy poziom abstrakcji do obsługi wątków , ale może szukasz czegoś bardziej podobnego do Akka ?
Aaron Cohn

8

Inną szybszą opcją do wywoływania rzeczy (takich jak DialogBox i MessageBox oraz tworzenie oddzielnych wątków dla metod niegwątkowych) byłoby użycie wyrażenia Lamba

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

3

Jakiś czas temu napisałem prostą klasę narzędziową, która korzysta z usługi wykonawczej JDK5 i wykonuje określone procesy w tle. Ponieważ doWork () zazwyczaj ma wartość zwracaną przez void, możesz chcieć użyć tej klasy narzędziowej, aby wykonać ją w tle.

Zobacz ten artykuł, w którym udokumentowałem to narzędzie.


6
Future and Callable robią to dla ciebie.
Amir Afghani

Tak, robią. idea polega na tym, aby wyodrębnić interfejs za asynchronicznym opakowaniem.
raja kolluru

Link jest uszkodzony (404).
palacsint

3

Aby to osiągnąć z RxJava 2.x, możesz użyć:

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

Te subscribeOn()określa, które scheduler metoda uruchomić akcję na - RxJava ma kilka predefiniowanych wyłącznika, tym Schedulers.io()który posiada gwint basen przeznaczony dla I / O operacji, i Schedulers.computation()który jest przeznaczony do intensywnej pracy procesora.


3

Jeśli używasz przynajmniej Java 8, możesz użyć metody runAsyncz klasy CompletableFuture

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

Jeśli chcesz zwrócić wynik, użyj supplyAsynczamiast tego

CompletableFuture.supplyAsync(() -> 1);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.