HashMap Vs. ConcurrentHashMap Vs. SynchronizedMap – Bagaimana HashMap dapat Disinkronkan di Java
Diterbitkan: 2015-01-29
HashMap
adalah struktur data yang sangat kuat di Jawa. Kami menggunakannya setiap hari dan hampir di semua aplikasi. Ada beberapa contoh yang telah saya tulis sebelumnya tentang Bagaimana Mengimplementasikan cache Threadsafe, Bagaimana cara mengubah Hashmap ke Arraylist?
Kami menggunakan Hashmap di kedua contoh di atas tetapi itu adalah kasus penggunaan Hashmap yang cukup sederhana. HashMap is a non-synchronized
.
Apakah Anda memiliki pertanyaan di bawah ini?
- Apa perbedaan antara ConcurrentHashMap dan Collections.synchronizedMap(Map)?
- Apa perbedaan antara ConcurrentHashMap dan Collections.synchronizedMap(Map) dalam hal kinerja?
- ConcurrentHashMap vs Collections.synchronizedMap()
- Pertanyaan wawancara HashMap dan ConcurrentHashMap Populer
Dalam tutorial ini kita akan membahas semua pertanyaan di atas dan alasan why and how
kita bisa Menyinkronkan Hashmap?
Mengapa?
Objek Peta adalah wadah asosiatif yang menyimpan elemen, dibentuk oleh kombinasi key
pengenal unik dan value
yang dipetakan . Jika Anda memiliki aplikasi konkuren yang sangat tinggi di mana Anda mungkin ingin mengubah atau membaca nilai kunci di utas yang berbeda, maka sangat ideal untuk menggunakan Hashmap Bersamaan. Contoh terbaik adalah Produsen Konsumen yang menangani baca/tulis secara bersamaan.
Jadi apa yang dimaksud dengan Peta thread-safe? Jika multiple threads
mengakses peta hash secara bersamaan, dan setidaknya salah satu utas memodifikasi peta secara struktural, itu must be synchronized externally
untuk menghindari tampilan konten yang tidak konsisten.
Bagaimana?
Ada dua cara untuk menyinkronkan HashMap
- Metode Java CollectionssynchronousMap()
- Gunakan ConcurrentHashMap
1 2 3 4 5 6 7 8 |
//Hashtable Map < String , String > normalMap = new Hashtable < String , String > ( ) ; //synchronizedMap synchronizedHashMap = Collections . synchronizedMap ( new HashMap < String , String > ( ) ) ; //ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap < String , String > ( ) ; |
PetaHashSerentak
- Anda harus menggunakan ConcurrentHashMap ketika Anda membutuhkan konkurensi yang sangat tinggi dalam proyek Anda.
- Ini aman tanpa menyinkronkan
whole map
. - Membaca bisa terjadi sangat cepat saat menulis dilakukan dengan kunci.
- Tidak ada penguncian di tingkat objek.
- Penguncian berada pada perincian yang jauh lebih halus pada level bucket hashmap.
- ConcurrentHashMap tidak melempar
ConcurrentModificationException
jika satu utas mencoba mengubahnya sementara yang lain mengulanginya. - ConcurrentHashMap menggunakan banyak kunci.
DisinkronkanHashMap
- Sinkronisasi pada level Object.
- 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.
Sekarang mari kita lihat kodenya
- Buat kelas
CrunchifyConcurrentHashMapVsSynchronizedHashMap.java
- Buat objek untuk setiap HashTable, SynchronizedMap dan CrunchifyConcurrentHashMap
- Tambahkan dan ambil 500 ribu entri dari Peta
- Ukur waktu mulai dan berakhir dan waktu tampilan dalam milidetik
- Kami akan menggunakan ExecutorService untuk menjalankan
5 threads
secara paralel
Berikut adalah kode Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
package crunchify . com . tutorials ; import java . util . Collections ; import java . util . HashMap ; import java . util . Hashtable ; import java . util . Map ; import java . util . concurrent . ConcurrentHashMap ; import java . util . concurrent . ExecutorService ; import java . util . concurrent . Executors ; import java . util . concurrent . TimeUnit ; /** * @author Crunchify.com * */ public class CrunchifyConcurrentHashMapVsSynchronizedMap { public final static int THREAD_POOL_SIZE = 5 ; public static Map < String , Integer > crunchifyHashTableObject = null ; public static Map < String , Integer > crunchifySynchronizedMapObject = null ; public static Map < String , Integer > crunchifyConcurrentHashMapObject = null ; public static void main ( String [ ] args ) throws InterruptedException { // Test with Hashtable Object crunchifyHashTableObject = new Hashtable < String , Integer > ( ) ; crunchifyPerformTest ( crunchifyHashTableObject ) ; // Test with synchronizedMap Object crunchifySynchronizedMapObject = Collections . synchronizedMap ( new HashMap < String , Integer > ( ) ) ; crunchifyPerformTest ( crunchifySynchronizedMapObject ) ; // Test with ConcurrentHashMap Object crunchifyConcurrentHashMapObject = new ConcurrentHashMap < String , Integer > ( ) ; crunchifyPerformTest ( crunchifyConcurrentHashMapObject ) ; } public static void crunchifyPerformTest ( final Map < String , Integer > crunchifyThreads ) throws InterruptedException { System . out . println ( "Test started for: " + crunchifyThreads . getClass ( ) ) ; long averageTime = 0 ; for ( int i = 0 ; i < 5 ; i ++ ) { long startTime = System . nanoTime ( ) ; ExecutorService crunchifyExServer = Executors . newFixedThreadPool ( THREAD_POOL_SIZE ) ; for ( int j = 0 ; j < THREAD_POOL_SIZE ; j ++ ) { crunchifyExServer . execute ( new Runnable ( ) { @SuppressWarnings ( "unused" ) @Override public void run ( ) { for ( int i = 0 ; i < 500000 ; i ++ ) { Integer crunchifyRandomNumber = ( int ) Math . ceil ( Math . random ( ) * 550000 ) ; // Retrieve value. We are not using it anywhere Integer crunchifyValue = crunchifyThreads . get ( String . valueOf ( crunchifyRandomNumber ) ) ; // Put value crunchifyThreads . put ( String . valueOf ( crunchifyRandomNumber ) , crunchifyRandomNumber ) ; } } } ) ; } // Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation // has no additional effect if already shut down. // This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that. crunchifyExServer . shutdown ( ) ; // Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is // interrupted, whichever happens first. crunchifyExServer . awaitTermination ( Long . MAX_VALUE , TimeUnit . DAYS ) ; long entTime = System . nanoTime ( ) ; long totalTime = ( entTime - startTime ) / 1000000L ; averageTime += totalTime ; System . out . println ( "500K entried added/retrieved in " + totalTime + " ms" ) ; } System . out . println ( "For " + crunchifyThreads . getClass ( ) + " the average time is " + averageTime / 5 + " ms\n" ) ; } } |

shutdown()
berarti layanan pelaksana tidak lagi menerima tugas yang masuk.-
awaitTermination()
dipanggil setelah permintaan shutdown.
Dan karenanya, Anda harus terlebih dahulu mematikan serviceExecutor dan kemudian memblokir dan menunggu utas selesai.
Hasil Konsol Eclipse:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Test started for: class java.util.Hashtable 500K entried added/retrieved in 1832 ms 500K entried added/retrieved in 1723 ms 500K entried added/retrieved in 1782 ms 500K entried added/retrieved in 1607 ms 500K entried added/retrieved in 1851 ms For class java.util.Hashtable the average time is 1759 ms Test started for: class java.util.Collections$SynchronizedMap 500K entried added/retrieved in 1923 ms 500K entried added/retrieved in 2032 ms 500K entried added/retrieved in 1621 ms 500K entried added/retrieved in 1833 ms 500K entried added/retrieved in 2048 ms For class java.util.Collections$SynchronizedMap the average time is 1891 ms Test started for: class java.util.concurrent.ConcurrentHashMap 500K entried added/retrieved in 1068 ms 500K entried added/retrieved in 1029 ms 500K entried added/retrieved in 1165 ms 500K entried added/retrieved in 840 ms 500K entried added/retrieved in 1017 ms For class java.util.concurrent.ConcurrentHashMap the average time is 1023 ms |