先看代码:
HashMap
package com.hash; import java.util.HashMap; import java.util.Map; public class HashMapTest { /** * NUMBER = 50,表示 50 个线程分别执行 put 方法 50 次 线程安全的情况下因该 map size 应该为 2500 */ public static final int NUMBER = 50; public static void main(String[] args) { Map<String, String> map = new HashMap<>(); for (int i = 0; i < NUMBER; i++) { new Thread(new HashMapTask(map)).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("map size = " + map.size()); } } class HashMapTask implements Runnable { Map<String, String> map; public HashMapTask(Map<String, String> map) { this.map = map; } @Override public void run() { for (int i = 0; i < HashMapTest.NUMBER; i++) { map.put(i + "-" + Thread.currentThread().getName(), "test"); } } }
运行结果:
开了 50 个线程往 HashMap
中添加元素,每个线程执行 50 次 put
方法,在线程安全的情况下,map
中应该有 2500 个键值对,但是执行的结果大都是小与 2500 的(并不会产生死循环)。
Hashtable
package com.hash; import java.util.Hashtable; public class HashTableTest { /** * NUMBER = 50,表示 50 个线程分别执行 put 方法 50 次 * 线程安全的情况下因该 table size 应该为 2500 */ public static final int NUMBER = 50; public static void main(String[] args) { Hashtable<String, String> table = new Hashtable<>(); for (int i = 0; i < NUMBER; i++) { new Thread(new HashTableTask(table)).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("table size = " + table.size()); } } class HashTableTask implements Runnable { Hashtable<String, String> table; public HashTableTask(Hashtable<String, String> table) { this.table = table; } @Override public void run() { for (int i = 0; i < HashTableTest.NUMBER; i++) { table.put(i + "-" + Thread.currentThread().getName(), "test"); } } }
运行结果:
无论运行多少次,结果都是size=2500。
ConcurrentHashMap
package com.hash; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class ConcurrentHashMapTest { /** * NUMBER = 50,表示 50 个线程分别执行 put 方法 50 次 线程安全的情况下因该 map size 应该为 2500 */ public static final int NUMBER = 50; public static void main(String[] args) { Map<String, String> map = new ConcurrentHashMap<>(); for (int i = 0; i < NUMBER; i++) { new Thread(new ConcurrentHashMapTask(map)).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("map size = " + map.size()); } } class ConcurrentHashMapTask implements Runnable { Map<String, String> map; public ConcurrentHashMapTask(Map<String, String> map) { this.map = map; } @Override public void run() { for (int i = 0; i < ConcurrentHashMapTest.NUMBER; i++) { map.put(i + "-" + Thread.currentThread().getName(), "test"); } } }
运行结果:
无论运行多少次,结果都是size=2500。
总结:
1.HashMap是线程不安全的。
2.Hashtable和ConcurrentHashMap是线程安全的。
我想线程安全但是我又想效率高?
使用 ConcurrentHashMap,其底层采用分段的数组+链表实现,线程安全,通过把 Map 分为 N 个 Segment(部分),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
Hashtable 之所以效率低主要是使用了 synchronized 关键字对 put 等操作进行加锁,而 synchronized 关键字加锁是对整张 Hash 表的,即每次锁住整张表让线程独占,致使效率低下,而 ConcurrentHashMap 在对象中保存了一个 Segment 数组,即将整个Hash表划分为多个分段;而每个Segment元素,即每个分段则类似于一个Hashtable;这样,在执行put操作时首先根据hash算法定位到元素属于哪个Segment,然后对该Segment加锁即可,因此, ConcurrentHashMap 在多线程并发编程中可是实现多线程put操作。
原文地址:https://www.cnblogs.com/gaopengpy/p/11916932.html
时间: 2024-10-10 07:46:26