Apa perbedaan antara ConcurrentHashMap dan Collections.synchronizedMap (Map)?

607

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, Hashtableadalah implementasi lama (memperluas Dictionarykelas usang ), yang telah diadaptasi kemudian agar sesuai dengan Mapantarmuka. 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 ConcurrentHashMaps? Yang mana yang cocok dengan situasi yang mana?

Henning
sumber
7
@SmilesinaJar Link saat ini rusak, berikut adalah salinan arsip dari artikel ini: Mengapa ConcurrentHashMap lebih baik daripada Hashtable dan sama baiknya dengan HashMap
informatik01
2
IBM: Bagaimana ConcurrentHashMap menawarkan konkurensi yang lebih tinggi tanpa mengorbankan keselamatan utas @ ibm.com/developerworks/java/library/j-jtp08223/…
pramodc84
FYI, Java 6 dibawa ConcurrentSkipListMapsebagai Mapimplementasi thread-safe lainnya . Dirancang untuk sangat bersamaan di bawah beban, menggunakan algoritma Daftar Lewati .
Basil Bourque

Jawaban:

423

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.

Yuval Adam
sumber
8
Melihat kode sumber, peta yang disinkronkan hanya implementasi dengan satu mutex (pemblokiran) sementara ConcurrentHashMap lebih kompleks untuk berurusan dengan akses bersamaan
Vinze
123
Harap perhatikan juga bahwa ConcurrentHashMap tidak mengizinkan kunci atau nilai nol. Jadi mereka BUKAN alternatif yang sama dari peta yang disinkronkan.
onejigtwojig
5
@AbdullahShaikh Masalah yang diangkat dalam artikel tersebut telah diperbaiki di Jawa 7 dan peningkatan lebih lanjut telah dilakukan di Jawa 8.
pulse0ne
5
@ Hengxin: segera setelah Anda melakukan operasi yang terdiri dari beberapa pertanyaan atau pembaruan peta atau ketika Anda mengulangi peta, Anda harus menyinkronkan peta secara manual untuk memastikan konsistensi. Peta yang disinkronkan menjamin konsistensi hanya untuk operasi tunggal (pemanggilan metode) pada peta, yang membuatnya lebih dari sering tidak berharga karena sebagian besar operasi kehidupan nyata adalah non-sepele sehingga Anda harus tetap menyinkronkan secara manual.
Holger
241
╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║ Thread-safety ║                   ║                                         ║
║   features    ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Mengenai mekanisme penguncian: Hashtable mengunci objek , sementara hanyaConcurrentHashMap mengunci ember .

Sergii Shevchyk
sumber
13
Hashtabletidak mengunci bagian peta. Lihatlah implementasinya. Ini menggunakan synchronizedkunci tanpa kunci yang disediakan sehingga pada dasarnya berarti mengunci keseluruhan hashtabledalam setiap operasi.
RMachnik
6
Bagaimana dengan Map yang disinkronkan?
Samuel Edwin Ward
3
Perilaku Collections.syncronizedMap seperti peta dukungan, kecuali semua metode ini aman untuk thread
Sergii Shevchyk
5
Saya akan mencetak tabel dan menjualnya masing-masing $ 5;). Bagus @shevchyk
realPK
Diedit: Tidak ada satupun yang sepenuhnya aman dari thread. Itu agak menyesatkan untuk pengembang yang lebih baru. Lihat: ibm.com/developerworks/java/library/j-jtp07233/index.html untuk memahami bahwa bahkan ConcurrentHashMap tidak sepenuhnya aman dari thread data eksternal. (misal: 1 utas menghapus nilai dan yang lain kemudian mencoba memeriksa apakah ada dan menempatkannya jika tidak. Itu adalah kondisi perlombaan data dan masih berarti bahwa meskipun menggunakan "ConcurrentHashMap" Anda tidak diringankan dari semua masalah keamanan utas.
Zombi
142

"Masalah skalabilitas" Hashtablehadir dengan cara yang persis sama Collections.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 ConcurrentHashMappenggunaan teknik yang sangat canggih untuk mengurangi kebutuhan untuk sinkronisasi dan memungkinkan paralel akses baca oleh beberapa thread tanpa sinkronisasi dan, yang lebih penting, memberikan Iteratoryang 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).

Michael Borgwardt
sumber
4
Nah, itu yang saya inginkan! :) Iterator yang tidak disinkronkan hanya manis semata! Thansk untuk info! :) (:
Kounavi
Jawaban yang bagus..tapi apakah artinya selama pengambilan utas tidak akan mendapatkan pembaruan terbaru karena utas pembaca tidak sinkron.
MrA
@MrA: Apakah Anda bertanya tentang ConcurrentHashMap? Dan apa yang Anda maksud dengan "pengambilan"?
Michael Borgwardt
4
@Michael Borgwardt untuk ConcurrentHashmap untuk mis. misalkan ada beberapa utas. beberapa dari mereka memperbarui Peta dan beberapa dari mereka mendapatkan data dari peta yang sama. JADI dalam skenario ini ketika utas sedang mencoba membaca apakah dijamin bahwa mereka akan mendapatkan data terbaru yang telah diperbarui karena utas pembaca tidak harus memegang kunci.
Tuan
35

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.

Bill Michell
sumber
2
Ya - sepertinya saya menyebutkan buku itu di setiap jawaban lain yang saya buat!
Bill Michell
Tautan @BillMichell rusak
@Govinda Matikan javascript sebelum mengakses tautan. Entri blog masih ada di sana!
Bill Michell
32

Perbedaan utama antara keduanya adalah bahwa ConcurrentHashMaphanya 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 memilih ConcurrentHashMap.

Juga satu perbedaan lainnya adalah bahwa ConcurrentHashMaptidak akan mempertahankan urutan elemen dalam Peta yang dilewati. Ini mirip dengan HashMapsaat menyimpan data. Tidak ada jaminan bahwa pesanan elemen dipertahankan. Meskipun Collections.synchronizedMap()akan mempertahankan urutan elemen dari peta yang diteruskan. Misalnya, jika Anda meneruskan TreeMapke ConcurrentHashMap, urutan elemen dalam ConcurrentHashMapmungkin tidak sama dengan urutan dalam TreeMap, tetapi Collections.synchronizedMap()akan mempertahankan urutan.

Lebih lanjut, ConcurrentHashMapdapat menjamin bahwa tidak ada yang ConcurrentModificationExceptionterlempar 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.

PixelsTech
sumber
13

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

Ramesh Papaganti
sumber
12

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.

Zach Scrivena
sumber
12

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.

Satish
sumber
dapatkah Anda melihat stackoverflow.com/questions/48579060/… ?
gstackoverflow
9

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:

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}

Namun, jangan berpikir itu ConcurrentHashMapadalah alternatif sederhana untuk HashMapdengan synchronizedblok khas seperti yang ditunjukkan di atas. Baca artikel ini untuk memahami seluk-beluknya dengan lebih baik.

Eljenso
sumber
7

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

Raj
sumber
7

Kita dapat mencapai keamanan utas dengan menggunakan ConcurrentHashMap dan sinkronisasiHashmap dan Hashtable. Tetapi ada banyak perbedaan jika Anda melihat arsitektur mereka.

  1. sinkronisasiHashmap dan Hashtable

Keduanya akan mempertahankan kunci di tingkat objek. Jadi jika Anda ingin melakukan operasi seperti put / get maka Anda harus mendapatkan kunci terlebih dahulu. Pada saat yang sama, utas lainnya tidak diizinkan untuk melakukan operasi apa pun. Jadi pada suatu waktu, hanya satu utas yang dapat beroperasi pada ini. Jadi waktu tunggu akan meningkat di sini. Kita dapat mengatakan bahwa kinerjanya relatif rendah ketika Anda membandingkan dengan ConcurrentHashMap.

  1. ConcurrentHashMap

Ini akan mempertahankan kunci di tingkat segmen. Ini memiliki 16 segmen dan mempertahankan level concurrency sebagai 16 secara default. Jadi pada suatu waktu, 16 utas dapat dapat beroperasi di ConcurrentHashMap. Selain itu, operasi baca tidak memerlukan kunci. Jadi sejumlah utas dapat melakukan operasi get di atasnya.

Jika thread1 ingin melakukan operasi put di segmen 2 dan thread2 ingin melakukan operasi put di segmen 4 maka diizinkan di sini. Berarti, 16 utas dapat melakukan operasi pemutakhiran (put / delete) pada ConcurrentHashMap sekaligus.

Sehingga waktu tunggu akan lebih sedikit di sini. Karenanya kinerjanya relatif lebih baik daripada Hashtable dan Hashtable yang disinkronkan.

Sumanth Varada
sumber
1
, 1. apa yang terjadi jika beberapa utas mencoba mengedit blok yang sama? 2. Apa yang terjadi jika katakan dua utas mencoba untuk membaca data dari blok yang sama di mana utas lain jika menulis data pada saat yang sama?
prnjn
6

ConcurrentHashMap

  • Anda harus menggunakan ConcurrentHashMap ketika Anda membutuhkan konkurensi yang sangat tinggi dalam proyek Anda.
  • Utas aman tanpa menyinkronkan seluruh peta.
  • Membaca dapat terjadi sangat cepat saat menulis dilakukan dengan kunci.
  • Tidak ada penguncian di tingkat objek.
  • Penguncian berada pada granularitas yang jauh lebih halus pada level bucket hashmap.
  • ConcurrentHashMap tidak melempar ConcurrentModificationException jika satu utas mencoba memodifikasinya sementara yang lain mengulanginya.
  • ConcurrentHashMap menggunakan banyak kunci.

SynchronizedHashMap

  • Sinkronisasi di tingkat Objek.
  • Setiap operasi baca / tulis perlu mendapatkan kunci.
  • Mengunci seluruh koleksi adalah overhead kinerja.
  • Ini pada dasarnya memberikan akses ke hanya satu utas ke seluruh peta & memblokir semua utas lainnya.
  • Ini dapat menyebabkan pertengkaran.
  • SynchronizedHashMap mengembalikan Iterator, yang gagal-cepat pada modifikasi bersamaan.

sumber

Premraj
sumber
4

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.

starblue
sumber
4

Ada satu fitur penting yang perlu diperhatikan ConcurrentHashMapselain fitur konkurensi yang disediakannya, yaitu iterator gagal-aman . Saya telah melihat pengembang menggunakan ConcurrentHashMaphanya 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.

Hai, India
sumber
3
  1. Jika Konsistensi Data sangat penting - Gunakan Hashtable atau Collections.synchronizedMap (Peta).
  2. Jika kecepatan / kinerja sangat penting dan Pembaruan Data dapat dikompromikan- Gunakan ConcurrentHashMap.
Shivam Maharshi
sumber
2

Secara umum, jika Anda ingin menggunakan ConcurrentHashMappastikan Anda siap untuk melewatkan 'pembaruan'
(yaitu mencetak konten HashMap tidak memastikan itu akan mencetak Peta yang terbaru) dan menggunakan API seperti CyclicBarrieruntuk memastikan konsistensi di seluruh program Anda. lingkaran kehidupan.

Kounavi
sumber
1

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.

infoj
sumber
1

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

Oleg Poltoratskii
sumber
0

Selain apa yang telah disarankan, saya ingin memposting kode sumber terkait SynchronizedMap.

Untuk membuat Maputas aman, kita bisa menggunakan Collections.synchronizedMappernyataan dan memasukkan instance peta sebagai parameter.

Implementasi synchronizedMapdalam Collectionsseperti di bawah ini

   public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
        return new SynchronizedMap<>(m);
    }

Seperti yang Anda lihat, Mapobjek input dibungkus oleh SynchronizedMapobjek.
Mari kita menggali implementasi SynchronizedMap,

 private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        private final Map<K,V> m;     // Backing Map
        final Object      mutex;        // Object on which to synchronize

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        public boolean containsKey(Object key) {
            synchronized (mutex) {return m.containsKey(key);}
        }
        public boolean containsValue(Object value) {
            synchronized (mutex) {return m.containsValue(value);}
        }
        public V get(Object key) {
            synchronized (mutex) {return m.get(key);}
        }

        public V put(K key, V value) {
            synchronized (mutex) {return m.put(key, value);}
        }
        public V remove(Object key) {
            synchronized (mutex) {return m.remove(key);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

        private transient Set<K> keySet;
        private transient Set<Map.Entry<K,V>> entrySet;
        private transient Collection<V> values;

        public Set<K> keySet() {
            synchronized (mutex) {
                if (keySet==null)
                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
                return keySet;
            }
        }

        public Set<Map.Entry<K,V>> entrySet() {
            synchronized (mutex) {
                if (entrySet==null)
                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
                return entrySet;
            }
        }

        public Collection<V> values() {
            synchronized (mutex) {
                if (values==null)
                    values = new SynchronizedCollection<>(m.values(), mutex);
                return values;
            }
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return m.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return m.hashCode();}
        }
        public String toString() {
            synchronized (mutex) {return m.toString();}
        }

        // Override default methods in Map
        @Override
        public V getOrDefault(Object k, V defaultValue) {
            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
        }
        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            synchronized (mutex) {m.forEach(action);}
        }
        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            synchronized (mutex) {m.replaceAll(function);}
        }
        @Override
        public V putIfAbsent(K key, V value) {
            synchronized (mutex) {return m.putIfAbsent(key, value);}
        }
        @Override
        public boolean remove(Object key, Object value) {
            synchronized (mutex) {return m.remove(key, value);}
        }
        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
        }
        @Override
        public V replace(K key, V value) {
            synchronized (mutex) {return m.replace(key, value);}
        }
        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
        }
        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
        }
        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.compute(key, remappingFunction);}
        }
        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
        }

        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

Apa yang SynchronizedMapdapat diringkas sebagai menambahkan kunci tunggal ke metode utama Mapobjek input . Semua metode yang dijaga oleh kunci tidak dapat diakses oleh banyak utas secara bersamaan. Itu berarti operasi normal suka putdan getdapat dieksekusi oleh utas tunggal pada saat yang sama untuk semua data dalam Mapobjek.

Itu membuat Mapobjek thread aman sekarang tetapi kinerja dapat menjadi masalah di beberapa skenario.

The ConcurrentMapini jauh lebih rumit dalam pelaksanaannya, kita dapat merujuk Membangun HashMap yang lebih baik untuk rincian. Singkatnya, ini diterapkan dengan mempertimbangkan keamanan dan kinerja thread.

Eugene
sumber