Saya perlu menjalankan sejumlah tugas 4 sekaligus, seperti ini:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
//...wait for completion somehow
Bagaimana saya bisa diberi tahu setelah semuanya selesai? Untuk saat ini saya tidak dapat memikirkan sesuatu yang lebih baik daripada mengatur beberapa penghitung tugas global dan menguranginya di akhir setiap tugas, kemudian monitor di loop tak terbatas penghitung ini menjadi 0; atau dapatkan daftar Futures dan dalam infinite loop monitor isDone untuk mereka semua. Apa solusi yang lebih baik yang tidak melibatkan loop tak terbatas?
Terima kasih.
Long.MAX_VALUE, TimeUnit.NANOSECONDS
setara dengan tidak memiliki batas waktu.java.util.concurrent
paket di bawah bagian: Untuk menunggu "selamanya", Anda dapat menggunakan nilaiTiming
Long.MAX_VALUE
Gunakan CountDownLatch :
dan dalam tugas Anda (lampirkan di coba / akhirnya)
sumber
ExecutorService.invokeAll()
melakukannya untukmu.sumber
futures
dikembalikan, tugas belum selesai. Mereka mungkin selesai di masa mendatang dan Anda akan memiliki tautan ke hasilnya. Itu sebabnya disebut aFuture
. Anda memiliki metode Future.get () , yang akan menunggu tugas selesai untuk mendapatkan hasil.Anda dapat menggunakan Daftar Futures, juga:
kemudian ketika Anda ingin bergabung dengan mereka semua, itu pada dasarnya setara dengan bergabung pada masing-masingnya, (dengan manfaat tambahan yang dimunculkan kembali pengecualian dari utas anak ke utama):
Pada dasarnya triknya adalah dengan memanggil .get () pada masing-masing Masa Depan satu per satu, alih-alih panggilan putaran tak terbatas isDone () on (semua atau masing-masing). Jadi, Anda dijamin "melanjutkan" melalui dan melewati blok ini segera setelah utas terakhir selesai. Peringatannya adalah bahwa sejak panggilan .get () membangkitkan kembali pengecualian, jika salah satu utas mati, Anda akan mengangkat dari ini mungkin sebelum utas lainnya selesai untuk menyelesaikan [untuk menghindari ini, Anda dapat menambahkan
catch ExecutionException
sekitar panggilan panggil ] Peringatan lainnya adalah ia membuat referensi ke semua utas jadi jika mereka memiliki variabel lokal utas mereka tidak akan dikumpulkan sampai setelah Anda melewati blok ini (meskipun Anda mungkin bisa mengatasi ini, jika itu menjadi masalah, dengan menghapus Masa depan dari ArrayList). Jika Anda ingin tahu Masa Depan mana yang "selesai dulu"https://stackoverflow.com/a/31885029/32453sumber
ExecutorCompletionService.take
: stackoverflow.com/a/11872604/199364Di Java8 Anda bisa melakukannya dengan CompletableFuture :
sumber
ExecutorService es = Executors.newFixedThreadPool(4); List< Future<?>> futures = new ArrayList<>(); for(Runnable task : taskList) { futures.add(es.submit(task)); } for(Future<?> future : futures) { try { future.get(); }catch(Exception e){ // do logging and nothing else } }
Hanya dua sen saya. Untuk mengatasi kebutuhan
CountDownLatch
untuk mengetahui jumlah tugas sebelumnya, Anda bisa melakukannya dengan cara lama dengan menggunakan yang sederhanaSemaphore
.Dalam tugas Anda, panggil saja
s.release()
seperti yang Anda inginkanlatch.countDown();
sumber
release
panggilan terjadi sebelumacquire
panggilan, tetapi setelah membaca dokumentasi Semaphore, saya melihat itu tidak masalah.Agak terlambat untuk pertandingan tapi demi penyelesaian ...
Alih-alih 'menunggu' untuk menyelesaikan semua tugas, Anda dapat berpikir dalam hal prinsip Hollywood, "jangan panggil aku, aku akan memanggilmu" - ketika aku selesai. Saya pikir kode yang dihasilkan lebih elegan ...
Jambu biji menawarkan beberapa alat yang menarik untuk mencapai hal ini.
Sebuah contoh ::
Bungkus ExecutorService ke dalam ListeningExecutorService ::
Kirim koleksi perlengkapan untuk eksekusi ::
Sekarang bagian penting:
Lampirkan panggilan balik ke ListenableFuture, yang dapat Anda gunakan untuk diberi tahu ketika semua masa depan selesai ::
Ini juga menawarkan keuntungan bahwa Anda dapat mengumpulkan semua hasil di satu tempat setelah pemrosesan selesai ...
Informasi lebih lanjut di sini
sumber
runOnUiThread()
dionSuccess()
.Kelas CyclicBarrier di Java 5 dan yang lebih baru dirancang untuk hal semacam ini.
sumber
Ikuti salah satu pendekatan di bawah ini.
submit
aktifExecutorService
dan periksa status dengan memblokir panggilanget()
padaFuture
objek seperti yang disarankan olehKiran
invokeAll()
pada ExecutorServiceshutdown, awaitTermination, shutdownNow
API ThreadPoolExecutor dalam urutan yang benarPertanyaan SE terkait:
Bagaimana CountDownLatch digunakan dalam Java Multithreading?
Cara mematikan java ExecutorService dengan benar
sumber
di sini ada dua pilihan, hanya sedikit bingung mana yang terbaik untuk pergi.
Pilihan 1:
Pilihan 2:
Di sini menempatkan future.get (); di coba tangkap adalah ide bagus bukan?
sumber
Anda bisa membungkus tugas Anda di runnable lain, yang akan mengirim pemberitahuan:
sumber
completed
penghitung. Jadi setelah memulai semuanya, pada setiap notifikasi, dapat menentukan apakah semua tugas telah selesai. Perhatikan bahwa sangat penting untuk digunakantry/finally
sehingga pemberitahuan selesai (atau pemberitahuan alternatif dicatch
blok) diberikan bahkan jika tugas gagal. Kalau tidak, akan menunggu selamanya.Saya baru saja menulis contoh program yang memecahkan masalah Anda. Tidak ada implementasi singkat yang diberikan, jadi saya akan menambahkannya. Meskipun Anda dapat menggunakan
executor.shutdown()
danexecutor.awaitTermination()
, ini bukan praktik terbaik karena waktu yang diambil oleh utas yang berbeda tidak dapat diprediksi.sumber
Hanya untuk memberikan lebih banyak alternatif di sini berbeda dengan menggunakan kait / penghalang. Anda juga bisa mendapatkan hasil parsial sampai semuanya selesai menggunakan CompletionService .
Dari Java Concurrency dalam praktiknya: "Jika Anda memiliki banyak perhitungan untuk diserahkan kepada Pelaksana dan Anda ingin mengambil hasilnya saat tersedia, Anda dapat mempertahankan Masa Depan yang terkait dengan setiap tugas dan berulang kali memilih penyelesaian dengan menelepon memanggil dengan batas waktu nol. Ini mungkin, tetapi membosankan . Untungnya ada cara yang lebih baik : layanan penyelesaian. "
Di sini implementasinya
sumber
Ini adalah solusi saya, berbasis di tip "AdamSkywalker", dan berhasil
sumber
Anda bisa menggunakan kode ini:
sumber
Saya membuat contoh kerja berikut. Idenya adalah memiliki cara untuk memproses kumpulan tugas (saya menggunakan antrian sebagai contoh) dengan banyak Thread (ditentukan secara terprogram oleh numberOfTasks / threshold), dan tunggu sampai semua Thread selesai untuk melanjutkan dengan beberapa pemrosesan lainnya.
Semoga ini bisa membantu!
sumber
Anda dapat menggunakan subclass Anda sendiri dari ExecutorCompletionService untuk membungkus
taskExecutor
, dan implementasi Anda sendiri BlockingQueue untuk mendapatkan informasi ketika setiap tugas menyelesaikan dan melakukan panggilan balik atau tindakan apa pun yang Anda inginkan ketika jumlah tugas yang diselesaikan mencapai tujuan yang Anda inginkan.sumber
Anda harus menggunakan
executorService.shutdown()
danexecutorService.awaitTermination
metode.Contohnya sebagai berikut:
sumber
Jadi saya posting jawaban saya dari pertanyaan terkait di sini, memetikan seseorang ingin cara yang lebih sederhana untuk melakukan ini
sumber
Java 8 - Kita bisa menggunakan stream API untuk memproses stream. Silakan lihat cuplikan di bawah ini
sumber
Jika
doSomething()
membuang beberapa pengecualian lain,latch.countDown()
sepertinya tidak akan mengeksekusi, jadi apa yang harus saya lakukan?sumber
jika Anda menggunakan lebih banyak utas, ExecutionServices SEQUENTIALLY dan ingin menunggu SETIAP EXECUTIONSERVICE selesai. Cara terbaik adalah seperti di bawah ini;
sumber
Ini mungkin bisa membantu
sumber
Anda bisa memanggil waitTillDone () di kelas Runner ini :
Anda dapat menggunakan kembali kelas ini dan memanggil waitTillDone () sebanyak yang Anda inginkan sebelum memanggil shutdown (), ditambah kode Anda sangat sederhana . Juga Anda tidak harus tahu dengan jumlah tugas dimuka.
Untuk menggunakannya cukup tambahkan
compile 'com.github.matejtymes:javafixes:1.3.1'
dependensi gradle / maven ini ke proyek Anda.Lebih detail dapat ditemukan di sini:
https://github.com/MatejTymes/JavaFixes
sumber
Ada metode dalam pelaksana
getActiveCount()
- yang memberikan jumlah utas aktif.Setelah merentangkan utas, kita dapat memeriksa apakah
activeCount()
nilainya0
. Setelah nilainya nol, artinya tidak ada utas aktif yang sedang berjalan yang berarti tugas selesai:sumber