Saya sedikit bingung tentang penggunaan yield()
metode di Java, khususnya pada contoh kode di bawah ini. Saya juga membaca bahwa yield () 'digunakan untuk mencegah eksekusi thread'.
Pertanyaan saya adalah:
Saya percaya kode di bawah ini menghasilkan output yang sama baik saat menggunakan
yield()
maupun saat tidak menggunakannya. Apakah ini benar?Sebenarnya, apa kegunaan utama dari
yield()
?Dalam hal apa yang
yield()
berbeda dari metodejoin()
daninterrupt()
?
Contoh kode:
public class MyRunnable implements Runnable {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
for(int i=0; i<5; i++) {
System.out.println("Inside main");
}
}
public void run() {
for(int i=0; i<5; i++) {
System.out.println("Inside run");
Thread.yield();
}
}
}
Saya mendapatkan output yang sama menggunakan kode di atas dengan dan tanpa menggunakan yield()
:
Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run
yield()
dan tidak. ketika Anda memiliki i besar daripada 5, Anda dapat melihat efekyield()
metode.Jawaban:
Sumber: http://www.javamex.com/tutorials/threads/yield.shtml
sumber
Saya melihat pertanyaan itu telah diaktifkan kembali dengan hadiah, sekarang menanyakan untuk apa kegunaan praktisnya
yield
. Saya akan memberikan contoh dari pengalaman saya.Seperti yang kita ketahui,
yield
memaksa thread pemanggil untuk melepaskan prosesor tempat ia berjalan sehingga thread lain dapat dijadwalkan untuk berjalan. Ini berguna ketika utas saat ini telah menyelesaikan tugasnya untuk saat ini tetapi ingin segera kembali ke depan antrean dan memeriksa apakah beberapa kondisi telah berubah. Apa yang membedakannya dari variabel kondisi?yield
memungkinkan utas kembali lebih cepat ke status berjalan. Saat menunggu pada variabel kondisi, utas ditangguhkan dan perlu menunggu utas yang berbeda untuk memberi sinyal bahwa itu harus dilanjutkan.yield
pada dasarnya mengatakan "izinkan utas yang berbeda untuk berjalan, tetapi izinkan saya untuk kembali bekerja segera karena saya mengharapkan sesuatu untuk berubah dalam keadaan saya dengan sangat cepat". Ini mengisyaratkan pemintalan yang sibuk, di mana suatu kondisi dapat berubah dengan cepat tetapi menangguhkan utas akan menyebabkan kinerja yang buruk.Tapi cukup mengoceh, inilah contoh konkretnya: pola paralel muka gelombang. Contoh dasar dari masalah ini adalah menghitung "pulau" individu 1s dalam larik dua dimensi yang diisi dengan 0s dan 1s. Sebuah "pulau" adalah sekumpulan sel yang berdekatan satu sama lain baik secara vertikal maupun horizontal:
Di sini kita memiliki dua pulau 1: kiri atas dan kanan bawah.
Solusi sederhananya adalah dengan membuat lintasan pertama di seluruh larik dan mengganti 1 nilai dengan penghitung tambahan sehingga pada akhirnya setiap 1 diganti dengan nomor urutnya dalam urutan mayor baris:
Pada langkah berikutnya, setiap nilai diganti dengan nilai minimum antara nilai itu sendiri dan nilai tetangganya:
Sekarang kita dapat dengan mudah menentukan bahwa kita memiliki dua pulau.
Bagian yang ingin kita jalankan secara paralel adalah langkah di mana kita menghitung minimum. Tanpa membahas terlalu banyak detail, setiap utas mendapatkan baris secara berselang-seling dan bergantung pada nilai yang dihitung oleh utas yang memproses baris di atas. Oleh karena itu, setiap utas perlu sedikit tertinggal di belakang utas yang memproses baris sebelumnya, tetapi juga harus mengikuti dalam waktu yang wajar. Lebih detail dan implementasinya disajikan sendiri dalam dokumen ini . Perhatikan penggunaan
sleep(0)
yang lebih atau kurang C setarayield
.Dalam hal
yield
ini digunakan untuk memaksa setiap utas secara bergiliran menjeda, tetapi karena utas yang memproses baris yang berdekatan akan maju dengan sangat cepat untuk sementara itu, variabel kondisi akan membuktikan pilihan yang menghancurkan.Seperti yang Anda lihat,
yield
ini adalah pengoptimalan butiran yang cukup halus. Penggunaannya di tempat yang salah misal menunggu pada kondisi yang jarang berubah akan menyebabkan penggunaan CPU yang berlebihan.Maaf atas ocehan panjangnya, semoga aku membuat diriku jelas.
sumber
yield
ketika kondisi tidak terpenuhi untuk memberikan kesempatan utas lain untuk melanjutkan komputasi, daripada menggunakan lebih tinggi- primitif sinkronisasi tingkat, bukan?yield
.Tentang perbedaan antara
yield()
,interrupt()
danjoin()
- secara umum, tidak hanya di Java:Khusus untuk Java, lihat
Bergabung:
Bagaimana cara menggunakan Thread.join? (di sini di StackOverflow)
Kapan bergabung dengan utas?
Menghasilkan:
Mengganggu:
Apakah Thread.interrupt () jahat? (di sini di StackOverflow)
sumber
wait()
bukanlah gabungan, ini tentang kunci pada objek yang coba diperoleh thread pemanggil - ia menunggu hingga kunci dibebaskan oleh orang lain dan telah diperoleh oleh utas. Tweak jawaban saya sesuai.Pertama, deskripsi sebenarnya adalah
Sekarang, kemungkinan besar utas utama Anda akan menjalankan perulangan lima kali sebelum
run
metode utas baru dijalankan, jadi semua panggilan keyield
hanya akan terjadi setelah perulangan di utas utama dijalankan.join
akan menghentikan utas saat ini hingga utas yang dipanggiljoin()
selesai dieksekusi.interrupt
akan mengganggu utas yang dipanggil, menyebabkan InterruptedException .yield
memungkinkan pengalihan konteks ke utas lain, jadi utas ini tidak akan menggunakan seluruh penggunaan CPU dari proses tersebut.sumber
SwitchToThread()
panggilan lebih baik daripada Tidur (0) dan ini seharusnya menjadi bug di Java :)Tidak ada perbedaan praktis
Thread.yield()
antara versi Java sejak 6 hingga 9.TL; DR;
Kesimpulan berdasarkan kode sumber OpenJDK ( http://hg.openjdk.java.net/ ).
Jika tidak mempertimbangkan dukungan HotSpot dari probe USDT (informasi pelacakan sistem dijelaskan dalam panduan dtrace ) dan properti JVM
ConvertYieldToSleep
maka kode sumberyield()
hampir sama. Lihat penjelasan di bawah ini.Jawa 9 :
Thread.yield()
memanggil metode khusus OSos::naked_yield()
:Di Linux:
Di Windows:
Java 8 dan sebelumnya:
Thread.yield()
memanggil metode khusus OSos::yield()
:Di Linux:
Di Windows:
Seperti yang Anda lihat,
Thread.yeald()
di Linux identik untuk semua versi Java.Mari kita lihat Windows
os::NakedYield()
dari JDK 8:Perbedaan antara Java 9 dan Java 8 di pemeriksaan tambahan keberadaan metode Win32 API
SwitchToThread()
. Kode yang sama hadir untuk Java 6.Kode sumber
os::NakedYield()
di JDK 7 sedikit berbeda tetapi memiliki perilaku yang sama:Pemeriksaan tambahan telah dibatalkan karena
SwitchToThread()
metode yang tersedia sejak Windows XP dan Windows Server 2003 (lihat catatan msdn ).sumber
Yield menyarankan kepada CPU bahwa Anda dapat menghentikan thread saat ini dan mulai menjalankan thread dengan prioritas lebih tinggi. Dengan kata lain, menetapkan nilai prioritas rendah ke utas saat ini untuk memberikan ruang bagi utas yang lebih penting.
TIDAK, keduanya akan menghasilkan hasil yang berbeda. Tanpa yield (), setelah thread mendapatkan kontrol, thread akan menjalankan loop 'Di dalam run' sekaligus. Namun, dengan yield (), setelah thread mendapatkan kontrol, thread akan mencetak 'Proses di dalam' sekali dan kemudian akan menyerahkan kontrol ke thread lain jika ada. Jika tidak ada utas yang tertunda, utas ini akan dilanjutkan lagi. Jadi setiap kali "Inside run 'dijalankan, ia akan mencari thread lain untuk dieksekusi dan jika tidak ada thread yang tersedia, thread saat ini akan terus dijalankan.
yield () adalah untuk memberikan ruang ke utas penting lainnya, join () untuk menunggu utas lain menyelesaikan eksekusinya, dan interrupt () untuk mengganggu utas yang sedang dieksekusi untuk melakukan sesuatu yang lain.
sumber
Without a yield(), once the thread gets control it will execute the 'Inside run' loop in one go
? Mohon klarifikasi.Thread.yield()
menyebabkan utas beralih dari status "Berjalan" ke status "Dapat dijalankan". Catatan: Ini tidak menyebabkan utas menjadi status "Menunggu".sumber
RUNNING
status untukjava.lang.Thread
contoh. Namun hal itu tidak menghalangi status "berjalan" asli untuk utas asli di mana suatuThread
instance adalah proxy.Thread.yield ()
Ikuti()
sumber
yield () utama digunakan untuk menunda aplikasi multi-threading.
semua perbedaan metode ini adalah yield () menempatkan utas ditunda saat menjalankan utas lain dan kembali setelah penyelesaian utas itu, join () akan membawa awal utas bersama-sama mengeksekusi sampai akhir dan utas lain untuk dijalankan setelah utas itu memiliki berakhir, interrupt () akan menghentikan eksekusi thread untuk sementara waktu.
sumber
yield
harus digunakan.