Saya memiliki objek dengan metode bernama StartDownload()
, yang dimulai tiga utas.
Bagaimana saya mendapat notifikasi ketika setiap utas telah selesai dieksekusi?
Apakah ada cara untuk mengetahui apakah satu (atau semua) utas sudah selesai atau masih dieksekusi?
java
multithreading
Ricardo Felgueiras
sumber
sumber
Jawaban:
Ada beberapa cara Anda dapat melakukan ini:
Bagaimana cara menerapkan Ide # 5? Nah, salah satu caranya adalah pertama-tama membuat antarmuka:
lalu buat kelas berikut:
dan kemudian masing-masing Thread Anda akan diperluas
NotifyingThread
dan alih-alih mengimplementasikannyarun()
akan menerapkandoRun()
. Jadi ketika mereka selesai, mereka akan secara otomatis memberi tahu siapa pun yang menunggu pemberitahuan.Terakhir, di kelas utama Anda - kelas yang memulai semua Thread (atau setidaknya objek yang menunggu pemberitahuan) - modifikasi kelas itu
implement ThreadCompleteListener
dan segera setelah membuat setiap Thread, tambahkan sendiri ke daftar pendengar:kemudian, saat setiap Thread keluar,
notifyOfThreadComplete
metode Anda akan dipanggil dengan instance Thread yang baru saja selesai (atau macet).Perhatikan bahwa lebih baik
implements Runnable
daripada daripadaextends Thread
karenaNotifyingThread
memperluas Thread biasanya tidak disarankan dalam kode baru. Tapi saya mengkode pertanyaan Anda. Jika Anda mengubahNotifyingThread
kelas untuk diimplementasikanRunnable
maka Anda harus mengubah beberapa kode Anda yang mengelola Thread, yang cukup mudah dilakukan.sumber
notify
metode tidak memasukkanrun
metode, tetapi setelah itu.Solusi menggunakan CyclicBarrier
label0 - penghalang siklik dibuat dengan jumlah pihak sama dengan jumlah utas pelaksana plus satu untuk utas utama pelaksanaan (di mana startDownload () dijalankan)
label 1 - n Download thThread memasuki ruang tunggu
label 3 - NUMBER_OF_DOWNLOADING_THREADS telah memasuki ruang tunggu. Utas utama eksekusi membebaskan mereka untuk mulai melakukan pekerjaan pengunduhan dalam waktu yang kurang lebih sama
label 4 - utas eksekusi masuk ke ruang tunggu. Ini adalah bagian 'paling sulit' dari kode yang harus dipahami. Tidak masalah utas mana yang akan memasuki ruang tunggu untuk kedua kalinya. Penting bahwa utas apa pun yang memasuki ruangan terakhir memastikan bahwa semua utas unduhan lainnya telah menyelesaikan pekerjaan pengunduhan mereka.
label 2 - Download nThth telah menyelesaikan pekerjaan pengunduhan dan memasuki ruang tunggu. Jika ini yang terakhir yaitu NUMBER_OF_DOWNLOADING_THREADS telah memasukkannya, termasuk utas utama eksekusi, utas utama akan melanjutkan eksekusi hanya ketika semua utas lainnya telah selesai mengunduh.
sumber
Anda harus benar - benar memilih solusi yang digunakan
java.util.concurrent
. Temukan dan baca Josh Bloch dan / atau Brian Goetz pada topik.Jika Anda tidak menggunakan
java.util.concurrent.*
dan bertanggung jawab untuk menggunakan Thread secara langsung, maka Anda mungkin harus menggunakannyajoin()
untuk mengetahui kapan sebuah thread selesai. Berikut adalah mekanisme Callback super sederhana. Pertama memperluasRunnable
antarmuka untuk memiliki panggilan balik:Kemudian buat seorang Pelaksana yang akan menjalankan runnable Anda dan memanggil Anda kembali setelah selesai.
Jenis hal lain yang jelas untuk ditambahkan ke
CallbackRunnable
antarmuka Anda adalah cara untuk menangani pengecualian, jadi mungkin letakkanpublic void uncaughtException(Throwable e);
garis di sana dan di pelaksana Anda, instal Thread.UncaughtExceptionHandler untuk mengirim Anda ke metode antarmuka itu.Tetapi melakukan semua yang benar-benar mulai berbau
java.util.concurrent.Callable
. Anda harus benar-benar melihat menggunakanjava.util.concurrent
jika proyek Anda mengizinkannya.sumber
runner.join()
dan kemudian kode apa pun yang Anda inginkan setelah itu, karena Anda tahu utasnya telah selesai. Apakah Anda hanya perlu mendefinisikan kode itu sebagai properti dari runnable, sehingga Anda dapat memiliki hal yang berbeda untuk runnable yang berbeda?runner.join()
adalah cara paling langsung untuk menunggu. Saya berasumsi OP tidak ingin memblokir utas panggilan utama mereka karena mereka meminta untuk "diberitahu" untuk setiap unduhan, yang dapat diselesaikan dalam urutan apa pun. Ini menawarkan satu cara untuk mendapatkan pemberitahuan secara tidak sinkron.Apakah Anda ingin menunggu sampai selesai? Jika demikian, gunakan metode Bergabung.
Ada juga properti isAlive jika Anda hanya ingin memeriksanya.
sumber
Thread
untukstart
, yang benang tidak, tapi panggilan kembali segera.isAlive
harus menjadi tes bendera sederhana, tetapi ketika saya googled metode itunative
.Anda bisa menginterogasi instance thread dengan getState () yang mengembalikan instance enumerasi Thread.State dengan salah satu nilai berikut:
Namun saya pikir itu akan menjadi desain yang lebih baik untuk memiliki thread utama yang menunggu 3 anak untuk menyelesaikan, master kemudian akan melanjutkan eksekusi ketika 3 lainnya selesai.
sumber
Anda juga bisa menggunakan
Executors
objek untuk membuat kumpulan utas ExecutorService . Kemudian gunakaninvokeAll
metode untuk menjalankan masing-masing utas Anda dan mengambil Futures. Ini akan memblokir sampai semua eksekusi selesai. Pilihan Anda yang lain adalah mengeksekusi masing-masing menggunakan pool dan kemudian memanggilawaitTermination
untuk memblokir sampai pool selesai dieksekusi. Pastikan untuk memanggilshutdown
() saat Anda selesai menambahkan tugas.sumber
Banyak hal telah diubah dalam 6 tahun terakhir di bagian multi-threading.
Alih-alih menggunakan
join()
dan mengunci API, Anda dapat menggunakan1. API ExecutorService
invokeAll()
2. CountDownLatch
3. ForkJoinPool atau
newWorkStealingPool()
di Pelaksana adalah cara lain4.Iterate melalui semua
Future
tugas dari menyerahkanExecutorService
dan memeriksa status dengan memblokir panggilanget()
padaFuture
objekLihat pertanyaan SE terkait:
Bagaimana cara menunggu utas yang memunculkan utas itu sendiri?
Pelaksana: Bagaimana cara menunggu secara sinkron sampai semua tugas selesai jika tugas dibuat secara rekursif?
sumber
Saya sarankan melihat javadoc untuk kelas Thread .
Anda memiliki banyak mekanisme untuk manipulasi utas.
Utas utama Anda dapat
join()
tiga utas secara berurutan, dan kemudian tidak akan dilanjutkan sampai ketiganya selesai.Polling status utas dari spawned utas pada interval waktu tertentu.
Letakkan semua utas yang muncul ke tempat terpisah
ThreadGroup
dan pollingactiveCount()
padaThreadGroup
dan tunggu sampai mencapai 0.Menyiapkan jenis panggilan balik kustom atau jenis antarmuka pendengar untuk komunikasi antar utas.
Saya yakin ada banyak cara lain yang masih saya lewatkan.
sumber
Inilah solusi yang sederhana, pendek, mudah dimengerti, dan bekerja dengan sempurna untuk saya. Saya perlu menggambar ke layar ketika utas lain berakhir; tetapi tidak bisa karena utas utama memiliki kendali atas layar. Begitu:
(1) Saya membuat variabel global:
boolean end1 = false;
Utas menyetelnya menjadi true saat mengakhiri. Itu diambil di mainthread oleh loop "postDelayed", di mana ia ditanggapi.(2) Utas saya berisi:
(3) Untungnya, "postDelayed" berjalan di utas utama, jadi di situlah di periksa utas lainnya sekali setiap detik. Ketika utas lainnya berakhir, ini dapat memulai apa pun yang ingin kita lakukan selanjutnya.
(4) Akhirnya, mulai semuanya berjalan di suatu tempat dalam kode Anda dengan memanggil:
sumber
Saya kira cara termudah adalah menggunakan
ThreadPoolExecutor
kelas.itulah yang kita butuhkan. Kami akan mengganti
afterExecute()
untuk mendapatkan panggilan balik setelah setiap utas selesai dan akan menimpaterminated()
untuk mengetahui kapan semua utas selesai.Jadi inilah yang harus Anda lakukan
Buat pelaksana:
Dan mulai utas Anda:
Metode di dalam
informUiThatWeAreDone();
melakukan apa pun yang perlu Anda lakukan ketika semua utas selesai, misalnya, perbarui UI.CATATAN: Jangan lupa tentang menggunakan
synchronized
metode karena Anda melakukan pekerjaan Anda secara paralel dan JADILAH SANGAT BERHATI-HATI jika Anda memutuskan untuk memanggilsynchronized
metode darisynchronized
metode lain ! Ini sering menyebabkan kebuntuanSemoga ini membantu!
sumber
Anda juga bisa menggunakan SwingWorker, yang memiliki dukungan perubahan properti bawaan. Lihat addPropertyChangeListener () atau metode get () untuk contoh perubahan pendengar keadaan.
sumber
Lihatlah dokumentasi Java untuk kelas Thread. Anda dapat memeriksa status utas. Jika Anda memasukkan ketiga utas ke dalam variabel anggota, maka ketiga utas tersebut dapat saling membaca status masing-masing.
Anda harus sedikit berhati-hati, karena Anda dapat menyebabkan kondisi balapan di antara utas. Coba saja hindari logika yang rumit berdasarkan keadaan utas lainnya. Jelas menghindari beberapa utas menulis ke variabel yang sama.
sumber