HashMap和ConcurrentHashMap数据结构

在多线程并发中,HashMap会造成线程不安全的问题,ConcurrentHashMap可以用于解决此类问题,接下来记录一下HashMap和ConcurrentHashMap的不同,加深一下印象
在jdk1.8之前,HashMap是由数据加链表的形式实现的,从整体来看,HashMap是一个数组,但是每个数据元素又是一张链表,如下图:
HashMap和ConcurrentHashMap数据结构
当向HashMap中增加元素时,会先根据新增的元素Key的hash值计算出该元素将要保存在数组中的下标,如果多个元素计算出的下标值相同,就会以链表的形式存储在数组的同一个元素中。
Jdk8之前的ConcurrentHashMap间接的实现了Map<K,V>,并将每一个元素称为一个segment,每个segment都是一个HashEntry<K,V>数组(称为table),table的每个元素都是一个HashEntry的单向队列,如下图:
HashMap和ConcurrentHashMap数据结构
默认情况下,ConcurrentHashMap会生成16个segment,采用这种结构的ConcurrentHashMap解决并发问题的思想是更加细粒度的结合给Map加锁,HashTable通过给整个容器加锁的方式保障线程安全,但是如果有多个线程同时修改HashTable仍然会发生写冲突并出现并发异常,而ConcurrentHashMap不会给整个容器加锁,而是给每个segment都加一把锁,即将一把大锁拆分成多把小锁来保证线程安全,这样在第一个线程修改segment-1的同时,其余线程也可以修改其余的segment,只要各个线程同一时刻访问的是不同的segment,就不会发生写冲突。
在jdk8中,HashMap和ConcurrentHashMap存储结构增加了红黑树,当链表中的元素超过8个的时候,HashMap就会将链表转换为红黑树,即数组加链表加红黑树的存储结构,如下图
HashMap和ConcurrentHashMap数据结构
同时,ConcurrentHashMap也改为了数据加链表加红黑树的存储结构,并且废弃了segment的加锁操作,采用了volatile HashEntry<K,V>对象保存数据,即对每一条数据直接通过volatile避免冲突,同时ConcurrentHashMap还使用了大量的synchronized和CAS算法来保证线程安全。

/**
 * 并发容器 - ConcurrentMap
 */
package concurrent.t06;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CountDownLatch;


public class Test_01_ConcurrentMap2 {
	
	public static void main(String[] args) {
//		final Map<String, String> map = new Hashtable<>();
		 final Map<String, String> billParamMap = new ConcurrentHashMap<>();
//		 final Map<String, String> map = new ConcurrentSkipListMap<>();
		final Random r = new Random();
		Thread[] array = new Thread[100];
		
		long begin = System.currentTimeMillis();
		for(int i = 0; i < array.length; i++){
			array[i] = new Thread(new Runnable() {
				@Override
				public void run() {
						billParamMap.put("hospitalId", "1");
						billParamMap.put("startTime", "20200926");
						billParamMap.put("endTime", "20200927");
						billParamMap.put("checkDate", "20200907");
				}
			});
		}
		for(Thread t : array){
			t.start();
		}
		long end = System.currentTimeMillis();
		System.out.println("执行时间为 : " + (end-begin) + "毫秒!");
		System.out.println(billParamMap.get("hospitalId"));
	}

}

结果为
HashMap和ConcurrentHashMap数据结构

上一篇:Ubuntu安装中文输入法


下一篇:高级Java开发技术!java运行结果窗口弹出来了