浅谈ConcurrentHashMap是怎么做到线程安全的


前言


随着互联网的发展追求高速度高并发在开发中已经成为日常。但是如何保证一致性成为一个很值得研究的课题,掌握同步容器在日常中的使用是必须的,下面的我将介绍ConcurrentHashMap,后续会介绍其他的同步容器


关键词

同步包装器(Synchronized Wrapper)
Queue
Deque
红黑树
分离锁
哈希

一、ConcurrentHashMap的定义

	一个支持并发存储的Key-Value容器。<br/>
	ConcurrentHashMap是允许我们在迭代时修改映射的映射实现。ConcurrentHashMap操作是线程安全的。ConcurrentHashMap不允许键和值为空。

二、应用场景

并发的同时操作一个容器的场景

三、扩展

HashMap的ConcurrentModificationException问题

package com.journaldev.util;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {

	public static void main(String[] args) {

		//ConcurrentHashMap
		Map<String,String> myMap = new ConcurrentHashMap<String,String>();
		myMap.put("1", "1");
		myMap.put("2", "1");
		myMap.put("3", "1");
		myMap.put("4", "1");
		myMap.put("5", "1");
		myMap.put("6", "1");
		System.out.println("ConcurrentHashMap before iterator: "+myMap);
		Iterator<String> it = myMap.keySet().iterator();

		while(it.hasNext()){
			String key = it.next();
			if(key.equals("3")) myMap.put(key+"new", "new3");
		}
		System.out.println("ConcurrentHashMap after iterator: "+myMap);

		//HashMap
		myMap = new HashMap<String,String>();
		myMap.put("1", "1");
		myMap.put("2", "1");
		myMap.put("3", "1");
		myMap.put("4", "1");
		myMap.put("5", "1");
		myMap.put("6", "1");
		System.out.println("HashMap before iterator: "+myMap);
		Iterator<String> it1 = myMap.keySet().iterator();

		while(it1.hasNext()){
			String key = it1.next();
			if(key.equals("3")) myMap.put(key+"new", "new3");
		}
		System.out.println("HashMap after iterator: "+myMap);
	}

}

Output:

ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
	at java.util.HashMap$KeyIterator.next(HashMap.java:828)
	at com.test.ConcurrentHashMapExample.main(ConcurrentHashMapExample.java:44

感兴趣的可参考:
链接: 详解.
HashMap使用不要修改会出现ConcurrentModificationException因为他采用的可能是快速失败策略。


Java 8中的变化

总体结构上,它的内部存储变得和我在专栏上一讲介绍的 HashMap 结构非常相似,同样是大的桶(bucket)数组,然后内部也是一个个所谓的链表结构(bin),同步的粒度要更细致一些。

其内部仍然有 Segment 定义,但仅仅是为了保证序列化时的兼容性而已,不再有任何结构上的用处。

因为不再使用 Segment,初始化操作大大简化,修改为 lazy-load 形式,这样可以有效避免初始开销,解决了老版本很多人抱怨的这一点。

数据存储利用 volatile 来保证可见性。

使用 CAS 等操作,在特定场景进行无锁并发操作。

使用 Unsafe、LongAdder 之类底层手段,进行极端情况的优化。

总结

1 jdk1.5之后添加ConcurrentHashMap并发功能为并发提供了更便捷的实现

猜你喜欢

转载自blog.csdn.net/aa327056812/article/details/109565386