jdk5.0以后提供了多种并发类容器来替代同步类容器从而改善性能。
同步类容器的状态都是串行化的。(100个请求,只有一个请求执行,执行后释放锁其他请求才能执行)
他们虽然实现了线程安全,但是严重降低了并发性,在多线程环境时,严重降低了应用程序的吞吐量。
1.ConcurrentMap
ConcurrentMap接口下有俩个重要的实现:
ConcurrentHashMap
ConcurrentSkipListMap(支持并发排序功能)
ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个
小的HashTable,它们有自己的锁。
只要多个修改操作发生在不同的段上,它们就可以并发进行。把一个整体分成了16个段
(Segment),也就是最高支持16个线程的并发修改操作。
这也是在多线程场景时减小锁的粒度从而降低锁竞争的一种方案。并且代码中大多共享
变量使用volatile关键字声明,目的是第一时间获取修改的内容,性能非常好。
如图:
一个线程想访问Segment(包含数据CD)如果对该段D操作,另外一个线程是对E操作两者不影响,如果第二个线程是对C操作就需要等待,每一个段Segment相当于一个同步容器HashTable
每次操作时候只是对段Segment加锁,同一段线程竞争等待
volatile的作用能实现整体公用资源共享,比如集合的大小长度
2.代码演示:
ConcurrentHashMap:map.putIfAbsent("k1", "vvv1");//元素已经存在则不去覆盖
package com.bfxy.thread.core.collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class UseConcurrentMap {
public static void main(String[] args) {
ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
map.put("k1", "v1");
map.put("k2", "v1");
map.put("k1", "vv1");
map.putIfAbsent("k1", "vvv1");//元素已经存在则不去覆盖
for(Map.Entry<String, Object> me : map.entrySet()){
System.err.println("key: " + me.getKey() + ", value: " + me.getValue());
}
map.size();
}
}