Bagaimana cara memanggil metode dengan utas terpisah di Jawa?

126

katakanlah saya punya metode doWork(). Bagaimana cara menyebutnya dari utas terpisah (bukan utas utama).

Louis Rhys
sumber
Kebetulan ada beberapa contoh atas pertanyaan terkait baru-baru ini: membunuh loop tak terbatas di java
Greg Hewgill
stackoverflow.com/questions/36832094/… Saya memiliki masalah serupa, tolong bantu saya menyelesaikannya
Sruthi Acg
Anda mungkin juga ingin melihat Reactive Java blog.danlew.net/2014/09/15/grokking-rxjava-part-1 untuk tugas asinkron
Nathan Dunn

Jawaban:

138

Buat kelas yang mengimplementasikan Runnableantarmuka. Letakkan kode yang ingin Anda jalankan di run()metode - itulah metode yang harus Anda tulis untuk mematuhi Runnableantarmuka. Dalam utas "utama" Anda, buat Threadkelas baru , meneruskan konstruktor sebuah instance dari Anda Runnable, lalu memanggilnya start(). startmemberi tahu JVM untuk melakukan keajaiban untuk membuat utas baru, lalu memanggil runmetode Anda di utas baru tersebut.

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

Lihatlah Jawa concurrency tutorial untuk memulai.

Jika metode Anda akan sering dipanggil, mungkin tidak ada gunanya membuat utas baru setiap kali, karena ini adalah operasi yang mahal. Mungkin akan lebih baik jika menggunakan semacam kumpulan utas. Silahkan lihat pada Future, Callable, Executorkelas dalam java.util.concurrentpaket.

Noel M
sumber
1
bagaimana jika ada variabel yang ingin Anda lewati?
Louis Rhys
8
The run()Metode tidak mengambil parameter, sehingga Anda tidak dapat melewati sebuah variabel di sana. Saya sarankan Anda meneruskannya di konstruktor - Saya akan mengedit jawaban saya untuk menunjukkannya.
Noel M
1
Apakah ada cara singkat untuk memanggil 1 metode di utas yang berbeda? Saya tahu new Thread() { public void run() {myMethod();}}.start();jalannya, apakah itu yang terpendek?
Steven Roose
@NoelM dapatkah Anda menjelaskan perbedaan antara jawaban Anda dan MANN?
Asif Mushtaq
2
Jawaban MANN menggunakan implementasi anonim Runnable- milikku adalah kelas yang diperluas Runnable. Dan karena saya telah melakukannya, saya memiliki konstruktor sendiri yang meneruskan status ke objek yang dipakai.
Noel M
183
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        // code goes here.
    }
});  
t1.start();

atau

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

atau

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

atau

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

atau

Executors.newCachedThreadPool().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});
MANN
sumber
Ini bekerja dengan sempurna untuk apa yang saya lakukan. Diperlukan untuk menjalankan layanan web dan memperbarui bilah kemajuan secara bersamaan menggunakan pola pengamat.
dpi
@Ashish: Jelaskan apa dan mengapa telah diedit?
MANN
1
@AshishAggarwal: Tampak aneh bagi saya ketika seseorang melakukannya tanpa izin dari penulis!
MANN
@ MANN dapatkah Anda menjelaskan mengapa Anda menggunakan metode run di parameter Thread? ada performa yang lebih baik?
Asif Mushtaq
1
Apakah kami perlu menghentikan utas secara eksplisit? Apakah tidak ada risiko membuat kebocoran memori dengan tidak menghentikan utas secara eksplisit? Atau apakah utas akan berhenti setelah selesai run()?
mereka
59

Di Java 8 Anda dapat melakukan ini dengan satu baris kode.

Jika metode Anda tidak mengambil parameter apa pun, Anda dapat menggunakan referensi metode:

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

Jika tidak, Anda bisa memanggil metode dalam ekspresi lambda:

new Thread(() -> doWork(someParam)).start();
Aaron Cohn
sumber
maaf untuk mengembalikan ini tapi apa sebenarnya ->artinya?
Kyle
1
Itu adalah sintaks yang digunakan untuk membuat ekspresi lambda. Lihat tautan berikut untuk info lebih lanjut: Apa fungsi '->' di Java? , dan The Java ™ Tutorials - Lambda Expressions
Aaron Cohn
@AaronCohn hal-hal hebat man! Apakah Anda tahu alternatif utas di Java? Saya berasal dari dunia Python, apa yang akan kami gunakan Celery task queueuntuk hal
CESCO
Java memiliki abstraksi tingkat yang lebih tinggi untuk menangani Threads , tetapi mungkin Anda mencari sesuatu yang lebih seperti Akka ?
Aaron Cohn
8

Opsi lain yang lebih cepat untuk memanggil sesuatu (seperti DialogBoxes dan MessageBoxes dan membuat utas terpisah untuk metode aman bukan utas) adalah dengan menggunakan Ekspresi Lamba

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

Beberapa waktu yang lalu, saya telah menulis kelas utilitas sederhana yang menggunakan layanan pelaksana JDK5 dan menjalankan proses tertentu di latar belakang. Karena doWork () biasanya memiliki nilai pengembalian void, Anda mungkin ingin menggunakan kelas utilitas ini untuk mengeksekusinya di latar belakang.

Lihat artikel ini di mana saya telah mendokumentasikan utilitas ini.

raja kolluru
sumber
6
Future dan Callable melakukan hal semacam ini untuk Anda.
Amir Afghani
Ya, benar. Idenya di sini adalah untuk mengabstraksi antarmuka di balik pembungkus asinkron.
raja kolluru
Tautannya rusak (404).
palacsint
3

Untuk mencapai ini dengan RxJava 2.x Anda dapat menggunakan:

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

The subscribeOn()Metode menentukan yang scheduler untuk menjalankan aksi di - RxJava memiliki beberapa penjadwal yang telah ditetapkan, termasuk Schedulers.io()yang telah thread kolam renang yang ditujukan untuk I / O operasi, dan Schedulers.computation()yang dimaksudkan untuk operasi intensif CPU.

Clyde
sumber
3

Jika Anda menggunakan setidaknya Java 8, Anda dapat menggunakan metode runAsyncdari kelas CompletableFuture

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

Jika Anda perlu kembali penggunaan hasil supplyAsyncbukan

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