Saya memiliki Peta yang akan dimodifikasi oleh beberapa utas secara bersamaan.
Tampaknya ada tiga implementasi Peta tersinkronisasi yang berbeda di Java API:
Hashtable
Collections.synchronizedMap(Map)
ConcurrentHashMap
Dari apa yang saya mengerti, Hashtable
adalah implementasi lama (memperluas Dictionary
kelas usang ), yang telah diadaptasi kemudian agar sesuai dengan Map
antarmuka. Sementara itu adalah disinkronkan, tampaknya memiliki serius masalah skalabilitas dan berkecil hati untuk proyek-proyek baru.
Tapi bagaimana dengan dua lainnya? Apa perbedaan antara Peta yang dikembalikan oleh Collections.synchronizedMap(Map)
dan ConcurrentHashMap
s? Yang mana yang cocok dengan situasi yang mana?
java
dictionary
concurrency
Henning
sumber
sumber
ConcurrentSkipListMap
sebagaiMap
implementasi thread-safe lainnya . Dirancang untuk sangat bersamaan di bawah beban, menggunakan algoritma Daftar Lewati .Jawaban:
Untuk kebutuhan Anda, gunakan
ConcurrentHashMap
. Hal ini memungkinkan modifikasi Peta secara bersamaan dari beberapa utas tanpa perlu memblokirnya.Collections.synchronizedMap(map)
membuat Peta pemblokiran yang akan menurunkan kinerja, meskipun memastikan konsistensi (jika digunakan dengan benar).Gunakan opsi kedua jika Anda perlu memastikan konsistensi data, dan setiap utas harus memiliki tampilan peta yang terbaru. Gunakan yang pertama jika kinerja sangat penting, dan setiap utas hanya menyisipkan data ke peta, dengan pembacaan yang lebih jarang terjadi.
sumber
Mengenai mekanisme penguncian:
Hashtable
mengunci objek , sementara hanyaConcurrentHashMap
mengunci ember .sumber
Hashtable
tidak mengunci bagian peta. Lihatlah implementasinya. Ini menggunakansynchronized
kunci tanpa kunci yang disediakan sehingga pada dasarnya berarti mengunci keseluruhanhashtable
dalam setiap operasi."Masalah skalabilitas"
Hashtable
hadir dengan cara yang persis samaCollections.synchronizedMap(Map)
- mereka menggunakan sinkronisasi yang sangat sederhana, yang berarti bahwa hanya satu utas yang dapat mengakses peta pada saat yang sama.Ini bukan masalah besar ketika Anda memiliki sisipan dan pencarian sederhana (kecuali Anda melakukannya dengan sangat intensif), tetapi menjadi masalah besar ketika Anda perlu mengulangi seluruh Peta, yang bisa memakan waktu lama untuk Peta besar - sementara satu utas melakukan itu, semua yang lain harus menunggu jika mereka ingin memasukkan atau mencari apa pun.
The
ConcurrentHashMap
penggunaan teknik yang sangat canggih untuk mengurangi kebutuhan untuk sinkronisasi dan memungkinkan paralel akses baca oleh beberapa thread tanpa sinkronisasi dan, yang lebih penting, memberikanIterator
yang tidak memerlukan sinkronisasi dan bahkan memungkinkan Peta untuk dimodifikasi selama interation (meskipun itu tidak memberikan jaminan apakah atau bukan elemen yang dimasukkan selama iterasi akan dikembalikan).sumber
ConcurrentHashMap lebih disukai ketika Anda dapat menggunakannya - meskipun setidaknya membutuhkan Java 5.
Ini dirancang untuk menskala dengan baik saat digunakan oleh banyak utas. Kinerja mungkin sedikit lebih buruk ketika hanya satu utas mengakses Peta pada satu waktu, tetapi secara signifikan lebih baik ketika beberapa utas mengakses peta secara bersamaan.
Saya menemukan entri blog yang mereproduksi tabel dari buku Java Concurrency In Practice yang sangat bagus , yang saya rekomendasikan sepenuhnya.
Collections.synchronizedMap masuk akal hanya jika Anda perlu membungkus peta dengan beberapa karakteristik lain, mungkin semacam peta yang diurutkan, seperti TreeMap.
sumber
Perbedaan utama antara keduanya adalah bahwa
ConcurrentHashMap
hanya akan mengunci bagian dari data yang sedang diperbarui sementara bagian lain dari data dapat diakses oleh utas lainnya. Namun,Collections.synchronizedMap()
akan mengunci semua data saat memperbarui, utas lainnya hanya dapat mengakses data saat kunci dilepaskan. Jika ada banyak operasi pembaruan dan relatif sedikit operasi baca, Anda harus memilihConcurrentHashMap
.Juga satu perbedaan lainnya adalah bahwa
ConcurrentHashMap
tidak akan mempertahankan urutan elemen dalam Peta yang dilewati. Ini mirip denganHashMap
saat menyimpan data. Tidak ada jaminan bahwa pesanan elemen dipertahankan. MeskipunCollections.synchronizedMap()
akan mempertahankan urutan elemen dari peta yang diteruskan. Misalnya, jika Anda meneruskanTreeMap
keConcurrentHashMap
, urutan elemen dalamConcurrentHashMap
mungkin tidak sama dengan urutan dalamTreeMap
, tetapiCollections.synchronizedMap()
akan mempertahankan urutan.Lebih lanjut,
ConcurrentHashMap
dapat menjamin bahwa tidak ada yangConcurrentModificationException
terlempar saat satu utas memperbarui peta dan utas lainnya melintasi iterator yang diperoleh dari peta. Namun,Collections.synchronizedMap()
ini tidak dijamin.Ada satu pos yang menunjukkan perbedaan keduanya dan juga
ConcurrentSkipListMap
.sumber
Peta Tersinkronisasi:
Synchronized Map juga tidak jauh berbeda dari Hashtable dan memberikan kinerja yang serupa dalam program Java bersamaan. Satu-satunya perbedaan antara Hashtable dan SynchronizedMap adalah bahwa SynchronizedMap bukan warisan dan Anda dapat membungkus Peta apa pun untuk membuat versi yang disinkronkan dengan menggunakan metode Collections.synchronizedMap ().
ConcurrentHashMap:
Kelas ConcurrentHashMap menyediakan versi bersamaan dari HashMap standar. Ini merupakan peningkatan pada fungsi tersinkronisasi yang disediakan di kelas Koleksi.
Tidak seperti Hashtable dan Synchronized Map, ia tidak pernah mengunci seluruh Peta, melainkan membagi peta dalam segmen dan penguncian dilakukan pada mereka. Ini bekerja lebih baik jika jumlah utas pembaca lebih besar dari jumlah utas penulis.
ConcurrentHashMap secara default dipisahkan menjadi 16 wilayah dan kunci diterapkan. Nomor default ini dapat diatur saat menginisialisasi instance ConcurrentHashMap. Saat mengatur data di segmen tertentu, kunci untuk segmen itu diperoleh. Ini berarti bahwa dua pembaruan masih dapat dijalankan secara bersamaan dengan aman jika masing-masing memengaruhi bucket terpisah, sehingga meminimalkan pertikaian kunci dan dengan demikian memaksimalkan kinerja.
ConcurrentHashMap tidak melempar ConcurrentModificationException
ConcurrentHashMap tidak melempar ConcurrentModificationException jika satu utas mencoba memodifikasinya sementara yang lain mengulanginya
Perbedaan antara synchornizedMap dan ConcurrentHashMap
Collections.synchornizedMap (HashMap) akan mengembalikan koleksi yang hampir setara dengan Hashtable, di mana setiap operasi modifikasi pada Peta dikunci pada objek Peta sementara dalam kasus ConcurrentHashMap, keamanan benang dicapai dengan membagi seluruh Peta menjadi partisi yang berbeda berdasarkan tingkat konkurensi dan hanya mengunci bagian tertentu alih-alih mengunci seluruh Peta.
ConcurrentHashMap tidak mengizinkan kunci nol atau nilai nol sementara HashMap yang disinkronkan memungkinkan satu kunci nol.
Tautan serupa
Tautan1
Link2
Perbandingan Kinerja
sumber
Hashtable
danConcurrentHashMap
jangan izinkannull
kunci ataunull
nilai.Collections.synchronizedMap(Map)
mensinkronisasikan semua operasi (get
,put
,size
, dll).ConcurrentHashMap
mendukung konkurensi pengambilan penuh, dan konkurensi yang diharapkan dapat disesuaikan untuk pembaruan.Seperti biasa, ada pengorbanan concurrency - overhead - speed yang terlibat. Anda benar-benar perlu mempertimbangkan persyaratan konkurensi terperinci dari aplikasi Anda untuk membuat keputusan, dan kemudian menguji kode Anda untuk melihat apakah itu cukup baik.
sumber
Di
ConcurrentHashMap
, kunci diterapkan ke segmen alih-alih seluruh Peta. Setiap segmen mengelola tabel hash internal sendiri. Kunci hanya diterapkan untuk operasi pembaruan.Collections.synchronizedMap(Map)
menyinkronkan seluruh peta.sumber
Anda benar tentang
HashTable
, Anda bisa melupakannya.Artikel Anda menyebutkan fakta bahwa sementara HashTable dan kelas pembungkus yang disinkronkan menyediakan keamanan utas dasar dengan hanya mengizinkan satu utas pada satu waktu untuk mengakses peta, ini bukan keselamatan utas 'sebenarnya' karena banyak operasi gabungan masih membutuhkan sinkronisasi tambahan, untuk contoh:
Namun, jangan berpikir itu
ConcurrentHashMap
adalah alternatif sederhana untukHashMap
dengansynchronized
blok khas seperti yang ditunjukkan di atas. Baca artikel ini untuk memahami seluk-beluknya dengan lebih baik.sumber
Berikut beberapa di antaranya:
1) ConcurrentHashMap hanya mengunci sebagian dari Peta tetapi SynchronizedMap mengunci seluruh MAp.
2) ConcurrentHashMap memiliki kinerja yang lebih baik daripada SynchronizedMap dan lebih skalabel.
3) Dalam hal multiple reader dan Single writer ConcurrentHashMap adalah pilihan terbaik.
Teks ini dari Perbedaan antara ConcurrentHashMap dan hashtabel di Jawa
sumber
Kita dapat mencapai keamanan utas dengan menggunakan ConcurrentHashMap dan sinkronisasiHashmap dan Hashtable. Tetapi ada banyak perbedaan jika Anda melihat arsitektur mereka.
sumber
ConcurrentHashMap
SynchronizedHashMap
sumber
sumber
ConcurrentHashMap dioptimalkan untuk akses bersamaan.
Akses tidak mengunci seluruh peta tetapi menggunakan strategi berbutir halus, yang meningkatkan skalabilitas. Ada juga peningkatan fungsional khusus untuk akses bersamaan, misalnya iterator bersamaan.
sumber
Ada satu fitur penting yang perlu diperhatikan
ConcurrentHashMap
selain fitur konkurensi yang disediakannya, yaitu iterator gagal-aman . Saya telah melihat pengembang menggunakanConcurrentHashMap
hanya karena mereka ingin mengedit entri - meletakkan / menghapus saat iterasi.Collections.synchronizedMap(Map)
tidak menyediakan iterator gagal-aman tetapi sebaliknya menyediakan iterator gagal-cepat . iterator fail-fast menggunakan snapshot ukuran peta yang tidak dapat diedit saat iterasi.sumber
sumber
Secara umum, jika Anda ingin menggunakan
ConcurrentHashMap
pastikan Anda siap untuk melewatkan 'pembaruan'(yaitu mencetak konten HashMap tidak memastikan itu akan mencetak Peta yang terbaru) dan menggunakan API seperti
CyclicBarrier
untuk memastikan konsistensi di seluruh program Anda. lingkaran kehidupan.sumber
Metode Collections.synchronizedMap () menyinkronkan semua metode HashMap dan secara efektif menguranginya menjadi struktur data di mana satu utas dapat masuk sekaligus karena mengunci setiap metode pada kunci umum.
Dalam sinkronisasi ConcurrentHashMap dilakukan sedikit berbeda. Daripada mengunci setiap metode pada kunci umum, ConcurrentHashMap menggunakan kunci terpisah untuk bucket terpisah sehingga hanya mengunci sebagian dari Peta. Secara default ada 16 bucket dan juga kunci terpisah untuk bucket terpisah. Jadi level konkurensi default adalah 16. Itu berarti secara teoritis setiap waktu 16 thread dapat mengakses ConcurrentHashMap jika mereka semua akan memisahkan bucket.
sumber
ConcurrentHashMap disajikan sebagai alternatif untuk Hashtable di Java 1.5 sebagai bagian dari paket konkurensi. Dengan ConcurrentHashMap, Anda memiliki pilihan yang lebih baik tidak hanya jika dapat digunakan dengan aman di lingkungan multi-thread bersamaan tetapi juga memberikan kinerja yang lebih baik daripada Hashtable dan sinkronisasi peta. ConcurrentHashMap berkinerja lebih baik karena mengunci bagian dari Peta. Ini memungkinkan operasi baca bersama dan pada saat yang sama menjaga integritas dengan menyinkronkan operasi penulisan.
Bagaimana ConcurrentHashMap diimplementasikan
ConcurrentHashMap dikembangkan sebagai alternatif Hashtable dan mendukung semua fungsionalitas Hashtable dengan kemampuan tambahan, yang disebut level concurrency. ConcurrentHashMap memungkinkan banyak pembaca untuk membaca secara bersamaan tanpa menggunakan blok. Ini menjadi mungkin dengan memisahkan Peta ke bagian yang berbeda dan memblokir hanya bagian dari Peta dalam pembaruan. Secara default, level konkurensi adalah 16, sehingga Peta dilebarkan ke 16 bagian dan setiap bagian dikelola oleh blok yang terpisah. Ini berarti, bahwa 16 utas dapat bekerja dengan Peta secara bersamaan, jika mereka bekerja dengan berbagai bagian Peta. Itu membuat ConcurrentHashMap hight produktif, dan tidak menurunkan keamanan thread.
Jika Anda tertarik pada beberapa fitur penting ConcurrentHashMap dan kapan Anda harus menggunakan realisasi Peta ini - Saya baru saja meletakkan tautan ke artikel yang bagus - Cara menggunakan ConcurrentHashMap di Jawa
sumber
Selain apa yang telah disarankan, saya ingin memposting kode sumber terkait
SynchronizedMap
.Untuk membuat
Map
utas aman, kita bisa menggunakanCollections.synchronizedMap
pernyataan dan memasukkan instance peta sebagai parameter.Implementasi
synchronizedMap
dalamCollections
seperti di bawah iniSeperti yang Anda lihat,
Map
objek input dibungkus olehSynchronizedMap
objek.Mari kita menggali implementasi
SynchronizedMap
,Apa yang
SynchronizedMap
dapat diringkas sebagai menambahkan kunci tunggal ke metode utamaMap
objek input . Semua metode yang dijaga oleh kunci tidak dapat diakses oleh banyak utas secara bersamaan. Itu berarti operasi normal sukaput
danget
dapat dieksekusi oleh utas tunggal pada saat yang sama untuk semua data dalamMap
objek.Itu membuat
Map
objek thread aman sekarang tetapi kinerja dapat menjadi masalah di beberapa skenario.The
ConcurrentMap
ini jauh lebih rumit dalam pelaksanaannya, kita dapat merujuk Membangun HashMap yang lebih baik untuk rincian. Singkatnya, ini diterapkan dengan mempertimbangkan keamanan dan kinerja thread.sumber