Bagaimana cara menggunakan ConcurrentLinkedQueue
di Java?
Dengan menggunakan ini LinkedQueue
, apakah saya perlu khawatir tentang konkurensi dalam antrian? Atau apakah saya hanya perlu mendefinisikan dua metode (satu untuk mengambil elemen dari daftar dan yang lainnya untuk menambahkan elemen ke daftar)?
Catatan: jelas kedua metode ini harus disinkronkan. Baik?
EDIT: Apa yang saya coba lakukan adalah ini: Saya memiliki kelas (di Java) dengan satu metode untuk mengambil item dari antrian dan kelas lain dengan satu metode untuk menambahkan item ke antrian. Item yang ditambahkan dan diambil dari daftar adalah objek kelas saya sendiri.
Satu pertanyaan lagi: apakah saya perlu melakukan ini dalam metode hapus:
while (queue.size() == 0){
wait();
queue.poll();
}
Saya hanya memiliki satu konsumen dan satu produsen.
sumber
Jawaban:
Tidak, metode tidak perlu disinkronkan, dan Anda tidak perlu menentukan metode apa pun; mereka sudah ada di ConcurrentLinkedQueue, gunakan saja. ConcurrentLinkedQueue melakukan semua operasi penguncian dan lainnya yang Anda butuhkan secara internal; produser Anda menambahkan data ke antrian, dan konsumen Anda melakukan polling untuk itu.
Pertama, buat antrian Anda:
Sekarang, di mana pun Anda membuat objek producer / consumer, teruskan antrian sehingga mereka memiliki tempat untuk meletakkan objek mereka (Anda dapat menggunakan setter untuk ini, sebagai gantinya, tetapi saya lebih suka melakukan hal semacam ini dalam konstruktor):
dan:
dan menambahkan barang ke dalamnya di produser Anda:
dan mengambil barang di konsumen Anda (jika antrian kosong, poll () akan mengembalikan null, jadi periksa):
Untuk info lebih lanjut lihat Javadoc
EDIT:
Jika Anda perlu memblokir menunggu antrian tidak kosong, Anda mungkin ingin menggunakan LinkedBlockingQueue , dan gunakan metode take (). Namun, LinkedBlockingQueue memiliki kapasitas maksimum (default ke Integer.MAX_VALUE, yang lebih dari dua miliar) dan dengan demikian mungkin atau mungkin tidak sesuai tergantung pada keadaan Anda.
Jika Anda hanya memiliki satu utas yang memasukkan barang ke antrean, dan utas lain mengambil barang dari antrean, ConcurrentLinkedQueue mungkin berlebihan. Lebih dari itu ketika Anda mungkin memiliki ratusan atau bahkan ribuan utas yang mengakses antrian pada saat yang bersamaan. Kebutuhan Anda mungkin akan dipenuhi dengan menggunakan:
Nilai plusnya adalah ia mengunci instans (antrian), sehingga Anda dapat menyinkronkan antrian untuk memastikan atomicity operasi gabungan (seperti dijelaskan oleh Jared). Anda TIDAK DAPAT melakukan ini dengan ConcurrentLinkedQueue, karena semua operasi dilakukan TANPA mengunci instance (menggunakan variabel java.util.concurrent.atomic). Anda TIDAK perlu melakukan ini jika Anda ingin memblokir saat antrian kosong, karena poll () hanya akan mengembalikan null saat antrian kosong, dan poll () adalah atom. Periksa untuk melihat apakah poll () mengembalikan null. Jika ya, tunggu (), lalu coba lagi. Tidak perlu dikunci.
Akhirnya:
Sejujurnya, saya baru saja menggunakan LinkedBlockingQueue. Ini masih berlebihan untuk aplikasi Anda, tetapi kemungkinan besar itu akan berfungsi dengan baik. Jika kinerjanya tidak cukup (PROFIL!), Anda selalu dapat mencoba yang lain, dan itu berarti Anda tidak perlu berurusan dengan hal-hal yang disinkronkan:
Yang lainnya sama. Put mungkin tidak akan memblokir, karena Anda tidak mungkin memasukkan dua miliar objek ke dalam antrean.
sumber
Collection.synchronizedList
mengembalikan aList
yang tidak diimplementasikanQueue
.ConcurrentLinkedQueue
ide yang bagus untuk Konsumen Produsen, saya mengacu pada posting ini stackoverflow.com/questions/1426754/…Ini sebagian besar merupakan duplikat dari pertanyaan lain .
Inilah bagian dari jawaban itu yang relevan dengan pertanyaan ini:
Apakah saya perlu melakukan sinkronisasi sendiri jika saya menggunakan java.util.ConcurrentLinkedQueue?
Operasi atom pada koleksi bersamaan disinkronkan untuk Anda. Dengan kata lain, setiap panggilan individu ke antrian dijamin thread-safe tanpa tindakan apa pun dari Anda. Yang tidak dijamin aman utas adalah operasi apa pun yang Anda lakukan pada koleksi yang non-atomik.
Misalnya, ini threadsafe tanpa tindakan apa pun dari Anda:
atau
Namun; panggilan non-atomic ke antrian tidak otomatis thread-safe. Misalnya, operasi berikut tidak otomatis threadsafe:
Yang terakhir bukanlah threadsafe, karena sangat mungkin bahwa antara waktu isEmpty dipanggil dan polling waktu dipanggil, thread lain akan menambahkan atau menghapus item dari antrian. Cara aman utas untuk melakukan ini adalah seperti ini:
Sekali lagi ... panggilan atomic ke antrian secara otomatis thread-safe. Panggilan non-atom tidak.
sumber
Gunakan polling untuk mendapatkan elemen pertama, dan tambahkan untuk menambahkan elemen terakhir baru. Itu saja, tidak ada sinkronisasi atau apa pun.
sumber
Ini mungkin yang Anda cari dalam hal keamanan utas & "kecantikan" saat mencoba mengonsumsi semua yang ada di antrean:
Ini akan menjamin bahwa Anda keluar saat antrian kosong, dan Anda terus mengeluarkan objek dari antrian tersebut selama tidak kosong.
sumber
ConcurentLinkedQueue adalah implementasi bebas menunggu / kunci yang sangat efisien (lihat javadoc untuk referensi), jadi tidak hanya Anda tidak perlu menyinkronkan, tetapi antrian tidak akan mengunci apa pun, sehingga hampir secepat non-sinkronisasi (bukan utas aman) satu.
sumber
Gunakan saja seperti yang Anda lakukan pada koleksi non-konkuren. Class Concurrent [Collection] membungkus koleksi reguler sehingga Anda tidak perlu memikirkan tentang sinkronisasi akses.
Edit: ConcurrentLinkedList sebenarnya bukan hanya pembungkus, tetapi lebih merupakan implementasi bersamaan yang lebih baik. Apa pun itu, Anda tidak perlu khawatir tentang sinkronisasi.
sumber