Katakanlah saya memiliki antrian penuh tugas yang harus saya serahkan ke layanan pelaksana. Saya ingin mereka diproses satu per satu. Cara paling sederhana yang bisa saya pikirkan adalah:
- Ambil tugas dari antrian
- Kirimkan ke pelaksana
- Panggil. Dapatkan di Masa Depan yang dikembalikan dan blokir hingga hasilnya tersedia
- Ambil tugas lain dari antrian ...
Namun, saya berusaha menghindari pemblokiran sepenuhnya. Jika saya memiliki 10.000 antrian seperti itu, yang membutuhkan tugas mereka diproses satu per satu, saya akan kehabisan ruang stack karena kebanyakan dari mereka akan berpegangan pada utas yang diblokir.
Yang saya inginkan adalah mengirimkan tugas dan memberikan panggilan balik yang dipanggil saat tugas selesai. Saya akan menggunakan notifikasi panggil itu sebagai bendera untuk mengirim tugas selanjutnya. (functionaljava dan jetlang tampaknya menggunakan algoritma non-blocking seperti itu, tetapi saya tidak dapat memahami kode mereka)
Bagaimana saya bisa melakukan itu menggunakan java.util.concurrent JDK, singkat menulis layanan pelaksana saya sendiri?
(antrian yang memberi saya tugas-tugas ini mungkin sendiri diblokir, tapi itu masalah yang harus ditangani kemudian)
Callback
antarmuka yang Anda nyatakan; bukan dari perpustakaan. Saat ini saya mungkin hanya menggunakanRunnable
,,Consumer
atauBiConsumer
, tergantung pada apa yang saya perlukan untuk beralih dari tugas ke pendengar.Di Java 8 Anda bisa menggunakan CompletableFuture . Berikut adalah contoh yang saya miliki dalam kode saya di mana saya menggunakannya untuk menjemput pengguna dari layanan pengguna saya, memetakannya ke objek tampilan saya dan kemudian memperbarui tampilan saya atau menampilkan dialog kesalahan (ini adalah aplikasi GUI):
Ini dijalankan secara tidak sinkron. Saya menggunakan dua metode pribadi:
mapUsersToUserViews
danupdateView
.sumber
Gunakan API masa depan yang dapat didengar Guava dan tambahkan callback. Lih dari situs web:
sumber
Anda bisa memperluas
FutureTask
kelas, dan menggantidone()
metode, lalu menambahkanFutureTask
objek keExecutorService
, sehinggadone()
metode akan memanggil ketikaFutureTask
selesai dengan segera.sumber
then add the FutureTask object to the ExecutorService
, bisakah Anda memberi tahu saya cara melakukan ini?ThreadPoolExecutor
juga memilikibeforeExecute
danafterExecute
mengaitkan metode yang dapat Anda timpa dan manfaatkan. Berikut adalah deskripsi dariThreadPoolExecutor
's Javadocs .sumber
Gunakan a
CountDownLatch
.Ini dari
java.util.concurrent
dan ini persis cara untuk menunggu beberapa utas untuk menyelesaikan eksekusi sebelum melanjutkan.Untuk mencapai efek panggilan balik yang Anda cari, itu memang membutuhkan sedikit kerja ekstra. Yaitu, menangani ini sendiri di utas terpisah yang menggunakan
CountDownLatch
dan tidak menunggu di atasnya, kemudian lanjutkan memberitahukan apa pun yang perlu Anda beri tahu. Tidak ada dukungan asli untuk panggilan balik, atau apa pun yang mirip dengan efek itu.EDIT: sekarang saya semakin memahami pertanyaan Anda, saya pikir Anda menjangkau terlalu jauh, tidak perlu. Jika Anda mengambil rutin
SingleThreadExecutor
, berikan semua tugas, dan itu akan melakukan antrian secara asli.sumber
Jika Anda ingin memastikan bahwa tidak ada tugas yang akan berjalan pada saat yang sama maka gunakan SingleThreadedExecutor . Tugas-tugas akan diproses sesuai urutan yang diajukan. Anda bahkan tidak perlu memegang tugas, cukup kirimkan ke eksekutif.
sumber
Kode sederhana untuk menerapkan
Callback
mekanisme menggunakanExecutorService
keluaran:
Catatan kunci:
newFixedThreadPool(5)
dengannewFixedThreadPool(1)
Jika Anda ingin memproses tugas berikutnya setelah menganalisis hasil dari
callback
tugas sebelumnya, hapus komentar di bawah iniAnda dapat mengganti
newFixedThreadPool()
dengan salah satu daritergantung pada kasus penggunaan Anda.
Jika Anda ingin menangani metode panggilan balik secara tidak sinkron
Sebuah. Berikan
ExecutorService or ThreadPoolExecutor
tugas yang dibagikan kepada Callableb. Ubah
Callable
metode Anda menjadiCallable/Runnable
tugasc. Dorong tugas panggilan balik ke
ExecutorService or ThreadPoolExecutor
sumber
Sekadar menambah jawaban Matt, yang membantu, berikut adalah contoh yang lebih lengkap untuk menunjukkan penggunaan panggilan balik.
Outputnya adalah:
sumber
Anda dapat menggunakan implementasi Callable sedemikian rupa sehingga
di mana CallbackInterface adalah sesuatu yang sangat mendasar
dan sekarang kelas utama akan terlihat seperti ini
sumber
Ini adalah ekstensi untuk jawaban Pache menggunakan Guava
ListenableFuture
.Secara khusus,
Futures.transform()
pengembalianListenableFuture
jadi dapat digunakan untuk melakukan panggilan async.Futures.addCallback()
kembalivoid
, jadi tidak dapat digunakan untuk rantai, tetapi bagus untuk menangani keberhasilan / kegagalan pada penyelesaian async.CATATAN: Selain merantai tugas async, Anda
Futures.transform()
juga dapat menjadwalkan setiap tugas pada pelaksana yang terpisah (Tidak ditampilkan dalam contoh ini).sumber