大数据Java

一起来聊聊 ConcurrentMap

2020-05-15  本文已影响0人  热衷技术的Java程序员

我们来看这个经常在多线程的情况下使用的这些个容器,从Map开始讲,Map经常用的有这么几个。

ConcurrentHashMap用hash表实现的这样一个高并发容器。

既然有了ConcurrentHashMap正常情况下就应该有ConcurrentTreeMap,你可以去查查,它没有,就等于缺了一块。

为什么没有呢?原因就是ConcurrentHashMap里面用的是cas操作,这个cas操作它用在tree的时候,用在树这个节点上的时候实现起来太复杂了,所以就没有这个ConcurrentTreeMap,但是有时间也需要这样一个排好序的Map, 那就有了ConcurrentSkipListMap跳表结构就出现了。

ConcurrentSkipListMap通过跳表来实现的高并发容器并且这个Map是有排序的。

跳表是什么样的结构呢?底层本身存储的元素一个链表,它是排好顺序的,大家知道当一个链表排好顺序的时候往里插入是特别困难的,查找的时候也特别麻烦,因为你得从头去遍历查找这个元素到底在哪里。

所以就出现了这个跳表的结构,底层是一个链表,链表查找的时候比较困难怎么办,那么我们在这些链表的基础上在拿出一些关键元素来,在上面做一层,那这个关键元素的这一层也是一个链表,那这个数量特别大的话在这个基础之上在拿一层出来再做一个链表, 每层链表的数据越来越少,而且它是分层,在我们查找的时候从顶层往下开始查找。

所以呢,查找容易了很多,同时它无锁的实现难度比TreeMap又容易很多,因此在JUC里面提供了ConcurrentSkipListMap这个类。

他们两个的区别一个是有序的一个是无序的,同时都支持并发的操作。下面这个小程序是一个效率的测试其实也没多大意义,大家可以去写一下跑跑。

importjava.util.*;

importjava.util.concurrent.ConcurrentHashMap;

importjava.util.concurrent.ConcurrentSkipListMap;

importjava.util.concurrent.CountDownLatch;

publicclassT01_ConcurrentMap{

publicstaticvoidmain(String[] args){

Map map = newConcurrentHashMap<>();

//Map<String, String> map = new ConcurrentSkipListMap<>(); //¸ß²¢·¢²¢ÇÒÅÅÐò

//Map<String, String> map = new Hashtable<>();

//Map<String, String> map = new HashMap<>(); //Collections.synchronizedXXX

//TreeMap

Random r = newRandom();

Thread[] ths = newThread[100];

CountDownLatch latch = newCountDownLatch(ths.length);

longstart = System.currentTimeMillis();

for(inti=0; i

ths[i] = newThread(()->{

for(intj=0; j<10000; j++) map.put("a"+ r.nextInt(100000), "a"+ r.nextInt(100000));

latch.countDown();

});

}

Arrays.asList(ths).forEach(t->t.start());

try{

latch.await();

} catch(InterruptedException e) {

e.printStackTrace();

}

longend = System.currentTimeMillis();

System.out.println(end - start);

System.out.println(map.size());

}

}

上一篇下一篇

猜你喜欢

热点阅读