Saya memiliki metode yang mengembalikan masa List
depan
List<Future<O>> futures = getFutures();
Sekarang saya ingin menunggu sampai semua futures selesai diproses dengan sukses atau salah satu tugas yang outputnya dikembalikan oleh pelemparan masa depan. Bahkan jika satu tugas melempar pengecualian, tidak ada gunanya menunggu untuk masa depan lainnya.
Pendekatan yang sederhana adalah dengan
wait() {
For(Future f : futures) {
try {
f.get();
} catch(Exception e) {
//TODO catch specific exception
// this future threw exception , means somone could not do its task
return;
}
}
}
Tapi masalahnya di sini adalah jika, misalnya, 4 masa depan melempar pengecualian, maka saya akan menunggu tidak perlu untuk 3 berjangka pertama yang akan tersedia.
Bagaimana cara mengatasinya? Apakah menghitung mundur kait akan membantu? Saya tidak dapat menggunakan Masa Depan isDone
karena kata java doc
boolean isDone()
Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.
java
multithreading
future
pengguna93796
sumber
sumber
ExecutionService
untuk setiap "batch" tugas, mengirimkannya ke sana, lalu segera mematikan layanan dan menggunakannyaawaitTermination()
, saya kira.CountDownLatch
jika Anda membungkus tubuh semua masa depan Anda dalamtry..finally
untuk memastikan kaitnya juga berkurang.Jawaban:
Anda dapat menggunakan CompletionService untuk menerima futures segera setelah mereka siap dan jika salah satu dari mereka melempar pengecualian membatalkan pemrosesan. Sesuatu seperti ini:
Saya pikir Anda dapat lebih meningkatkan untuk membatalkan tugas yang masih berjalan jika salah satu dari mereka melakukan kesalahan.
sumber
CompletionService
.Jika Anda menggunakan Java 8 maka Anda dapat melakukan ini dengan lebih mudah dengan CompletableFuture dan CompletableFuture.allOf , yang menerapkan panggilan balik hanya setelah semua CompletableFutures yang disediakan selesai.
sumber
Future
instance, Anda tidak dapat menerapkan metode ini. Tidak mudah dikonversiFuture
menjadiCompletableFuture
.Gunakan
CompletableFuture
di Java 8sumber
Anda dapat menggunakan ExecutorCompletionService . Dokumentasi tersebut bahkan memiliki contoh kasus penggunaan yang tepat:
Yang penting untuk diperhatikan di sini adalah bahwa ecs.take () akan mendapatkan tugas yang selesai pertama , bukan hanya yang pertama kali disampaikan. Dengan demikian Anda harus mendapatkannya dalam urutan menyelesaikan eksekusi (atau melempar pengecualian).
sumber
Jika Anda menggunakan Java 8 dan tidak ingin memanipulasi
CompletableFuture
, saya telah menulis alat untuk mengambil hasil untukList<Future<T>>
streaming menggunakan. Kuncinya adalah Anda dilarang melakukanmap(Future::get)
lemparan.Ini membutuhkan
AggregateException
yang berfungsi seperti C # 'sKomponen ini bertindak persis seperti Task.WaitAll C # . Saya sedang mengerjakan varian yang melakukan hal yang sama
CompletableFuture.allOf
(equivalento toTask.WhenAll
)Alasan mengapa saya melakukan ini adalah karena saya menggunakan Spring
ListenableFuture
dan tidak ingin port keCompletableFuture
meskipun itu adalah cara yang lebih standarsumber
Jika Anda ingin menggabungkan Daftar CompletableFutures, Anda bisa melakukan ini:
Untuk detail lebih lanjut tentang Future & CompletableFuture, tautan berguna:
1. Masa Depan: https://www.baeldung.com/java-future
2. CompletableFuture: https://www.baeldung.com/java-completablefuture
3. CompletableFuture: https : //www.callicoder.com/java-8-completablefuture-tutorial/
sumber
mungkin ini akan membantu (tidak ada yang akan diganti dengan utas mentah, yeah!) Saya sarankan menjalankan setiap
Future
orang dengan utas terpisah (mereka berjalan paralel), maka ketika salah satu dari kesalahan didapat, itu hanya memberi sinyal manajer (Handler
kelas).Saya harus mengatakan kode di atas akan error (tidak memeriksa), tapi saya harap saya bisa menjelaskan solusinya. tolong coba.
sumber
sumber
CompletionService akan mengambil Callables Anda dengan metode .submit () dan Anda dapat mengambil futures yang dihitung dengan metode .take ().
Satu hal yang tidak boleh Anda lupakan adalah menghentikan ExecutorService dengan memanggil metode .shutdown (). Anda juga hanya dapat memanggil metode ini ketika Anda telah menyimpan referensi ke layanan pelaksana jadi pastikan untuk menyimpannya.
Kode contoh - Untuk sejumlah item pekerjaan yang harus dikerjakan secara paralel:
Kode contoh - Untuk sejumlah item pekerjaan yang dinamis untuk dikerjakan secara paralel:
sumber
Saya memiliki kelas utilitas yang berisi ini:
Setelah Anda memilikinya, menggunakan impor statis, Anda dapat dengan mudah menunggu semua berjangka seperti ini:
Anda juga dapat mengumpulkan semua hasil mereka seperti ini:
Hanya meninjau kembali pos lama saya dan memperhatikan bahwa Anda memiliki kesedihan lain:
Dalam hal ini, solusi sederhana adalah melakukan ini secara paralel:
Dengan cara ini pengecualian pertama, meskipun tidak akan menghentikan masa depan, akan merusak pernyataan forEach, seperti pada contoh serial, tetapi karena semua menunggu secara paralel, Anda tidak perlu menunggu 3 yang pertama selesai.
sumber
sumber