Bisakah saya mendapatkan skenario sederhana lengkap yaitu tutorial yang menyarankan bagaimana ini harus digunakan, khususnya dengan Antrian?
Metode wait()
dan notify()
dirancang untuk menyediakan mekanisme untuk memungkinkan thread untuk memblokir sampai kondisi tertentu terpenuhi. Untuk ini saya menganggap Anda ingin menulis implementasi antrian pemblokiran, di mana Anda memiliki beberapa elemen penyimpanan cadangan ukuran tetap.
Hal pertama yang harus Anda lakukan adalah mengidentifikasi kondisi yang Anda inginkan metode menunggu. Dalam hal ini, Anda ingin put()
metode untuk memblokir sampai ada ruang kosong di toko, dan Anda ingin take()
metode untuk memblokir hingga ada beberapa elemen untuk kembali.
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(T element) throws InterruptedException {
while(queue.size() == capacity) {
wait();
}
queue.add(element);
notify(); // notifyAll() for multiple producer/consumer threads
}
public synchronized T take() throws InterruptedException {
while(queue.isEmpty()) {
wait();
}
T item = queue.remove();
notify(); // notifyAll() for multiple producer/consumer threads
return item;
}
}
Ada beberapa hal yang perlu diperhatikan tentang cara Anda harus menggunakan mekanisme menunggu dan memberi tahu.
Pertama, Anda perlu memastikan bahwa panggilan apa pun ke wait()
atau notify()
berada dalam wilayah kode yang disinkronkan (dengan wait()
dan notify()
panggilan disinkronkan pada objek yang sama). Alasan untuk ini (selain masalah keamanan ulir standar) adalah karena sesuatu yang dikenal sebagai sinyal yang terlewat.
Contoh dari ini, adalah bahwa sebuah thread dapat memanggil put()
ketika antrian kebetulan penuh, kemudian memeriksa kondisi, melihat bahwa antrian penuh, namun sebelum dapat memblokir utas lain dijadwalkan. Utas kedua ini lalu take()
elemen dari antrian, dan memberi tahu utas tunggu bahwa antrian tidak lagi penuh. Namun, karena utas pertama sudah memeriksa kondisinya, ia hanya akan memanggil wait()
setelah dijadwalkan ulang, meskipun itu dapat membuat kemajuan.
Dengan menyinkronkan pada objek bersama, Anda dapat memastikan bahwa masalah ini tidak terjadi, karena take()
panggilan utas kedua tidak akan dapat membuat kemajuan sampai utas pertama benar-benar diblokir.
Kedua, Anda perlu menempatkan kondisi yang Anda periksa dalam loop sementara, bukan pernyataan if, karena masalah yang dikenal sebagai wake-up palsu. Di sinilah utas tunggu kadang-kadang dapat diaktifkan kembali tanpa notify()
dipanggil. Menempatkan pemeriksaan ini dalam loop sementara akan memastikan bahwa jika wake-up palsu terjadi, kondisinya akan diperiksa ulang, dan utas akan menelepon wait()
lagi.
Seperti beberapa jawaban lain yang disebutkan, Java 1.5 memperkenalkan perpustakaan konkurensi baru (dalam java.util.concurrent
paket) yang dirancang untuk memberikan abstraksi tingkat yang lebih tinggi atas mekanisme menunggu / memberi tahu. Dengan menggunakan fitur-fitur baru ini, Anda dapat menulis ulang contoh aslinya seperti:
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public void put(T element) throws InterruptedException {
lock.lock();
try {
while(queue.size() == capacity) {
notFull.await();
}
queue.add(element);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
lock.lock();
try {
while(queue.isEmpty()) {
notEmpty.await();
}
T item = queue.remove();
notFull.signal();
return item;
} finally {
lock.unlock();
}
}
}
Tentu saja jika Anda benar-benar membutuhkan antrian pemblokiran, maka Anda harus menggunakan implementasi antarmuka BlockingQueue .
Juga, untuk hal-hal seperti ini saya sangat merekomendasikan Java Concurrency in Practice , karena mencakup semua yang Anda ingin tahu tentang masalah dan solusi terkait concurrency.
notify
bangun hanya satu utas. Jika dua utas konsumen bersaing untuk menghapus suatu elemen, satu pemberitahuan dapat membangunkan utas konsumen lainnya, yang tidak dapat berbuat apa-apa dan akan kembali tidur (alih-alih produsen, yang kami harapkan akan memasukkan elemen baru.) Karena utas produser tidak dibangunkan, tidak ada yang dimasukkan dan sekarang ketiga utas akan tidur tanpa batas. Saya menghapus komentar saya sebelumnya karena dikatakan (salah) bahwa bangun palsu adalah penyebab masalah (Tidak.)Bukan contoh antrian, tapi sangat sederhana :)
Beberapa poin penting:
1) TIDAK PERNAH lakukan
Selalu gunakan saat (kondisi), karena
while(!pizzaExists){ wait(); }
.2) Anda harus memegang kunci (disinkronkan) sebelum memanggil tunggu / nofity. Thread juga harus mendapatkan kunci sebelum bangun.
3) Cobalah untuk menghindari memperoleh kunci apa pun di dalam blok Anda yang disinkronkan dan berusaha untuk tidak memanggil metode asing (metode yang Anda tidak tahu pasti apa yang mereka lakukan). Jika Anda harus, pastikan untuk mengambil langkah-langkah untuk menghindari kebuntuan.
4) Hati-hati dengan memberi tahu (). Tetap dengan notifyAll () sampai Anda tahu apa yang Anda lakukan.
5) Terakhir, namun tidak kalah pentingnya, baca Java Concurrency in Practice !
sumber
pizzaArrived
bendera? jika bendera diubah tanpa panggilan kenotify
sana tidak akan berpengaruh. Juga hanya denganwait
dannotify
memanggil contoh berfungsi.synchronized
kata kunci, itu berlebihan untuk mendeklarasikan variabelvolatile
, dan direkomendasikan untuk menghindarinya untuk menghindari kebingungan @mridaMeskipun Anda meminta
wait()
dannotify()
secara spesifik, saya merasa bahwa kutipan ini masih cukup penting:Josh Bloch, Java Edisi 2 Efektif , Butir 69: Memilih utilitas konkurensi ke
wait
dannotify
(penekanannya):sumber
notify()
danwait()
lagiSudahkah Anda melihat Tutorial Java ini ?
Lebih lanjut, saya menyarankan Anda untuk menjauh dari bermain dengan hal-hal semacam ini dalam perangkat lunak nyata. Baik untuk bermain dengannya sehingga Anda tahu apa itu, tetapi concurrency memiliki jebakan di semua tempat. Lebih baik menggunakan abstraksi level yang lebih tinggi dan koleksi yang disinkronkan atau antrian JMS jika Anda membuat perangkat lunak untuk orang lain.
Setidaknya itulah yang saya lakukan. Saya bukan ahli konkurensi jadi saya tinggal menangani benang dengan tangan sedapat mungkin.
sumber
Contoh
sumber
Contoh untuk wait () dan notifyall () di Threading.
Daftar array statis tersinkronisasi digunakan sebagai sumber daya dan metode menunggu () dipanggil jika daftar array kosong. metode notify () dipanggil setelah elemen ditambahkan untuk daftar array.
sumber
if(arrayList.size() == 0)
, saya pikir itu mungkin kesalahan di sini.