- 浏览: 150166 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
EclipseEye:
fair_jm 写道不错 蛮详细的 谢谢分享
SWT/JFace专题 --- SWT中Display和多线程 -
fair_jm:
不错 蛮详细的 谢谢分享
SWT/JFace专题 --- SWT中Display和多线程
Map
------
1.HashMap
2.LinkedHashMap
3.IdentityHashMap
4.WeakHashMap
5.TreeMap
6.EnumMap
7.ConcurrentHashMap
8.ConcurrentSkipListMap
--------------------------------------
------------------ConcurrentSkipListMap-----------------
ConcurrentSkipListMap提供了一种线程安全的并发访问的排序映射表。内部是SkipList(跳表)结构实现,在理论上能够在O(log(n))时间内完成查找、插入、删除操作。
SkipList是一种红黑树的替代方案,由于SkipList与红黑树相比无论从理论和实现都简单许多,所以得到了很好的推广。SkipList是基于一种统计学原理实现的,有可能出现最坏情况,即查找和更新操作都是O(n)时间复杂度,但从统计学角度分析这种概率极小。
使用SkipList类型的数据结构更容易控制多线程对集合访问的处理,因为链表的局部处理性比较好,当多个线程对SkipList进行更新操作(指插入和删除)时,SkipList具有较好的局部性,每个单独的操作,对整体数据结构影响较小。而如果使用红黑树,很可能一个更新操作,将会波及整个树的结构,其局部性较差。因此使用SkipList更适合实现多个线程的并发处理。
在非多线程的情况下,应当尽量使用TreeMap。此外对于并发性相对较低的并行程序可以使用Collections.synchronizedSortedMap将TreeMap进行包装,也可以提供较好的效率。对于高并发程序,应当使用ConcurrentSkipListMap,能够提供更高的并发度。
所以在多线程程序中,如果需要对Map的键值进行排序时,请尽量使用ConcurrentSkipListMap,可能得到更好的并发度。
注意,调用ConcurrentSkipListMap的size时,由于多个线程可以同时对映射表进行操作,所以映射表需要遍历整个链表才能返回元素个数,这个操作是个O(log(n))的操作。
ConcurrentSkipListMap存储结构
ConcurrentSkipListMap存储结构图
跳跃表(SkipList):(如上图所示)
1.多条链构成,是关键字升序排列的数据结构;
2.包含多个级别,一个head引用指向最高的级别,最低(底部)的级别,包含所有的key;
3.每一个级别都是其更低级别的子集,并且是有序的;
4.如果关键字 key在 级别level=i中出现,则,level<=i的链表中都会包含该关键字key;
------------------------
ConcurrentSkipListMap主要用到了Node和Index两种节点的存储方式,通过volatile关键字实现了并发的操作
------------------------
ConcurrentSkipListMap的查找
通过SkipList的方式进行查找操作:(下图以“查找91”进行说明:)
红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;
ConcurrentSkipListMap的删除
通过SkipList的方式进行删除操作:(下图以“删除23”进行说明:)
红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;
ConcurrentSkipListMap的插入
通过SkipList的方式进行插入操作:(下图以“添加55”的两种情况,进行说明:)
在level=2(该level存在)的情况下添加55的图示:只需在level<=2的合适位置插入55即可
--------
在level=4(该level不存在,图示level4是新建的)的情况下添加55的情况:首先新建level4,然后在level<=4的合适位置插入55
-----------
------
1.HashMap
2.LinkedHashMap
3.IdentityHashMap
4.WeakHashMap
5.TreeMap
6.EnumMap
7.ConcurrentHashMap
8.ConcurrentSkipListMap
--------------------------------------
------------------ConcurrentSkipListMap-----------------
ConcurrentSkipListMap提供了一种线程安全的并发访问的排序映射表。内部是SkipList(跳表)结构实现,在理论上能够在O(log(n))时间内完成查找、插入、删除操作。
SkipList是一种红黑树的替代方案,由于SkipList与红黑树相比无论从理论和实现都简单许多,所以得到了很好的推广。SkipList是基于一种统计学原理实现的,有可能出现最坏情况,即查找和更新操作都是O(n)时间复杂度,但从统计学角度分析这种概率极小。
使用SkipList类型的数据结构更容易控制多线程对集合访问的处理,因为链表的局部处理性比较好,当多个线程对SkipList进行更新操作(指插入和删除)时,SkipList具有较好的局部性,每个单独的操作,对整体数据结构影响较小。而如果使用红黑树,很可能一个更新操作,将会波及整个树的结构,其局部性较差。因此使用SkipList更适合实现多个线程的并发处理。
在非多线程的情况下,应当尽量使用TreeMap。此外对于并发性相对较低的并行程序可以使用Collections.synchronizedSortedMap将TreeMap进行包装,也可以提供较好的效率。对于高并发程序,应当使用ConcurrentSkipListMap,能够提供更高的并发度。
所以在多线程程序中,如果需要对Map的键值进行排序时,请尽量使用ConcurrentSkipListMap,可能得到更好的并发度。
注意,调用ConcurrentSkipListMap的size时,由于多个线程可以同时对映射表进行操作,所以映射表需要遍历整个链表才能返回元素个数,这个操作是个O(log(n))的操作。
ConcurrentSkipListMap存储结构
ConcurrentSkipListMap存储结构图
跳跃表(SkipList):(如上图所示)
1.多条链构成,是关键字升序排列的数据结构;
2.包含多个级别,一个head引用指向最高的级别,最低(底部)的级别,包含所有的key;
3.每一个级别都是其更低级别的子集,并且是有序的;
4.如果关键字 key在 级别level=i中出现,则,level<=i的链表中都会包含该关键字key;
------------------------
ConcurrentSkipListMap主要用到了Node和Index两种节点的存储方式,通过volatile关键字实现了并发的操作
static final class Node<K,V> { final K key; volatile Object value;//value值 volatile Node<K,V> next;//next引用 …… } static class Index<K,V> { final Node<K,V> node; final Index<K,V> down;//downy引用 volatile Index<K,V> right;//右边引用 …… }
------------------------
ConcurrentSkipListMap的查找
通过SkipList的方式进行查找操作:(下图以“查找91”进行说明:)
红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;
/get方法,通过doGet操作实现 public V get(Object key) { return doGet(key); } //doGet的实现 private V doGet(Object okey) { Comparable<? super K> key = comparable(okey); Node<K,V> bound = null; Index<K,V> q = head;//把头结点作为当前节点的前驱节点 Index<K,V> r = q.right;//前驱节点的右节点作为当前节点 Node<K,V> n; K k; int c; for (;;) {//遍历 Index<K,V> d; // 依次遍历right节点 if (r != null && (n = r.node) != bound && (k = n.key) != null) { if ((c = key.compareTo(k)) > 0) {//由于key都是升序排列的,所有当前关键字大于所要查找的key时继续向右遍历 q = r; r = r.right; continue; } else if (c == 0) { //如果找到了相等的key节点,则返回该Node的value如果value为空可能是其他并发delete导致的,于是通过另一种 //遍历findNode的方式再查找 Object v = n.value; return (v != null)? (V)v : getUsingFindNode(key); } else bound = n; } //如果一个链表中right没能找到key对应的value,则调整到其down的引用处继续查找 if ((d = q.down) != null) { q = d; r = d.right; } else break; } // 如果通过上面的遍历方式,还没能找到key对应的value,再通过Node.next的方式进行查找 for (n = q.node.next; n != null; n = n.next) { if ((k = n.key) != null) { if ((c = key.compareTo(k)) == 0) { Object v = n.value; return (v != null)? (V)v : getUsingFindNode(key); } else if (c < 0) break; } } return null; }------------------------------------------------
ConcurrentSkipListMap的删除
通过SkipList的方式进行删除操作:(下图以“删除23”进行说明:)
红色虚线,表示查找的路径,蓝色向右箭头表示right引用;黑色向下箭头表示down引用;
//remove操作,通过doRemove实现,把所有level中出现关键字key的地方都delete掉 public V remove(Object key) { return doRemove(key, null); } final V doRemove(Object okey, Object value) { Comparable<? super K> key = comparable(okey); for (;;) { Node<K,V> b = findPredecessor(key);//得到key的前驱(就是比key小的最大节点) Node<K,V> n = b.next;//前驱节点的next引用 for (;;) {//遍历 if (n == null)//如果next引用为空,直接返回 return null; Node<K,V> f = n.next; if (n != b.next) // 如果两次获得的b.next不是相同的Node,就跳转到第一层循环重新获得b和n break; Object v = n.value; if (v == null) { // 当n被其他线程delete的时候,其value==null,此时做辅助处理,并重新获取b和n n.helpDelete(b, f); break; } if (v == n || b.value == null) // 当其前驱被delet的时候直接跳出,重新获取b和n break; int c = key.compareTo(n.key); if (c < 0) return null; if (c > 0) {//当key较大时就继续遍历 b = n; n = f; continue; } if (value != null && !value.equals(v)) return null; if (!n.casValue(v, null)) break; if (!n.appendMarker(f) || !b.casNext(n, f))//casNext方法就是通过比较和设置b(前驱)的next节点的方式来实现删除操作 findNode(key); // 通过尝试findNode的方式继续find else { findPredecessor(key); // Clean index if (head.right == null) //如果head的right引用为空,则表示不存在该level tryReduceLevel(); } return (V)v; } } }-------------------------------------
ConcurrentSkipListMap的插入
通过SkipList的方式进行插入操作:(下图以“添加55”的两种情况,进行说明:)
在level=2(该level存在)的情况下添加55的图示:只需在level<=2的合适位置插入55即可
--------
在level=4(该level不存在,图示level4是新建的)的情况下添加55的情况:首先新建level4,然后在level<=4的合适位置插入55
-----------
//put操作,通过doPut实现 public V put(K key, V value) { if (value == null) throw new NullPointerException(); return doPut(key, value, false); } private V doPut(K kkey, V value, boolean onlyIfAbsent) { Comparable<? super K> key = comparable(kkey); for (;;) { Node<K,V> b = findPredecessor(key);//前驱 Node<K,V> n = b.next; //定位的过程就是和get操作相似 for (;;) { if (n != null) { Node<K,V> f = n.next; if (n != b.next) // 前后值不一致的情况下,跳转到第一层循环重新获得b和n break;; Object v = n.value; if (v == null) { // n被delete的情况下 n.helpDelete(b, f); break; } if (v == n || b.value == null) // b 被delete的情况,重新获取b和n break; int c = key.compareTo(n.key); if (c > 0) { b = n; n = f; continue; } if (c == 0) { if (onlyIfAbsent || n.casValue(v, value)) return (V)v; else break; // restart if lost race to replace value } // else c < 0; fall through } Node<K,V> z = new Node<K,V>(kkey, value, n); if (!b.casNext(n, z)) break; // restart if lost race to append to b int level = randomLevel();//得到一个随机的level作为该key-value插入的最高level if (level > 0) insertIndex(z, level);//进行插入操作 return null; } } } /** * 获得一个随机的level值 */ private int randomLevel() { int x = randomSeed; x ^= x << 13; x ^= x >>> 17; randomSeed = x ^= x << 5; if ((x & 0x8001) != 0) // test highest and lowest bits return 0; int level = 1; while (((x >>>= 1) & 1) != 0) ++level; return level; } //执行插入操作:如上图所示,有两种可能的情况: //1.当level存在时,对level<=n都执行insert操作 //2.当level不存在(大于目前的最大level)时,首先添加新的level,然后在执行操作1 private void insertIndex(Node<K,V> z, int level) { HeadIndex<K,V> h = head; int max = h.level; if (level <= max) {//情况1 Index<K,V> idx = null; for (int i = 1; i <= level; ++i)//首先得到一个包含1~level个级别的down关系的链表,最后的inx为最高level idx = new Index<K,V>(z, idx, null); addIndex(idx, h, level);//把最高level的idx传给addIndex方法 } else { // 情况2 增加一个新的级别 level = max + 1; Index<K,V>[] idxs = (Index<K,V>[])new Index[level+1]; Index<K,V> idx = null; for (int i = 1; i <= level; ++i)//该步骤和情况1类似 idxs[i] = idx = new Index<K,V>(z, idx, null); HeadIndex<K,V> oldh; int k; for (;;) { oldh = head; int oldLevel = oldh.level; if (level <= oldLevel) { // lost race to add level k = level; break; } HeadIndex<K,V> newh = oldh; Node<K,V> oldbase = oldh.node; for (int j = oldLevel+1; j <= level; ++j) newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);//创建新的 if (casHead(oldh, newh)) { k = oldLevel; break; } } addIndex(idxs[k], oldh, k); } } /** *在1~indexlevel层中插入数据 */ private void addIndex(Index<K,V> idx, HeadIndex<K,V> h, int indexLevel) { // insertionLevel 代表要插入的level,该值会在indexLevel~1间遍历一遍 int insertionLevel = indexLevel; Comparable<? super K> key = comparable(idx.node.key); if (key == null) throw new NullPointerException(); // 和get操作类似,不同的就是查找的同时在各个level上加入了对应的key for (;;) { int j = h.level; Index<K,V> q = h; Index<K,V> r = q.right; Index<K,V> t = idx; for (;;) { if (r != null) { Node<K,V> n = r.node; // compare before deletion check avoids needing recheck int c = key.compareTo(n.key); if (n.value == null) { if (!q.unlink(r)) break; r = q.right; continue; } if (c > 0) { q = r; r = r.right; continue; } } if (j == insertionLevel) {//在该层level中执行插入操作 // Don't insert index if node already deleted if (t.indexesDeletedNode()) { findNode(key); // cleans up return; } if (!q.link(r, t))//执行link操作,其实就是inset的实现部分 break; // restart if (--insertionLevel == 0) { // need final deletion check before return if (t.indexesDeletedNode()) findNode(key); return; } } if (--j >= insertionLevel && j < indexLevel)//key移动到下一层level t = t.down; q = q.down; r = q.right; } } }
发表评论
-
Nio Socket
2013-05-16 05:53 0asfda -
结合jdk源码解读,Error Exception
2013-05-10 04:00 0/* * @(#)Error.java 1.17 05/11 ... -
从不同的角度,重新审视class和interface
2013-05-07 03:40 0java开发中,对应class和interface的基本区别都 ... -
java.lang.Object
2013-05-07 03:35 0/* * @(#)Object.java 1.73 06/0 ... -
反射机制+类加载机制
2013-02-18 01:30 0反射机制+类加载机制 -
并发专题----使用开源软件Amino构建并发应用程序/多线程运行时分析工具MTRAT
2013-02-14 00:50 1377使用开源软件构建并发 ... -
并发专题 ---- 线程安全
2013-02-14 00:50 753线程安全 ================== ... -
并发专题 --- 锁
2013-02-14 00:50 805相比于synchronized,ReentrantLock 提 ... -
并发专题 ----(JMM)java内存模型
2013-02-14 00:50 542Java 内存模型 ------------ ... -
并发专题 ---java.util.concurrent 包
2013-02-13 02:26 1840java.util.concurrent 包 原 ... -
集合框架 Queue篇(8)---PriorityBlockingQueue、SynchronousQueue
2013-02-07 12:40 1316Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(7)---LinkedBlockingDeque
2013-02-07 12:40 853Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(6)---LinkedBlockingQueue
2013-02-07 12:39 834Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(5)---ArrayBlockingQueue
2013-02-06 10:39 706Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(4)---阻塞队列和生产者-消费者模式、DelayQueue
2013-02-06 10:39 998Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(3)---ConcurrentLinkedQueue
2013-02-06 10:38 1050Queue ------------ 1.ArrayDequ ... -
集合框架 Queue篇(2)---PriorityQueue
2013-02-06 10:38 835Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(1)---ArrayDeque
2013-02-06 10:38 932Queue ------------ 1.ArrayDeq ... -
集合框架 Set篇---HashSet、LinkedHashSet、TreeSet、CopyOnWriteArraySet、ConcurrentSkipList
2013-02-05 08:43 1484Set --------- 1.HashSet 2.Link ... -
集合框架 List篇(2)---CopyOnWriteArrayList
2013-02-05 08:43 843List ----------- 1.ArrayList(jd ...
相关推荐
Java集合框架是Java编程语言中不可或缺的一部分,它提供了一种高效、灵活的方式来存储和操作数据。面试中,Java集合框架的题目通常会测试应聘者对数据结构、算法以及API的理解。以下是对Java集合框架的一些核心知识...
Java集合框架是Java编程语言中用于存储和操作对象的一个强大工具。它提供了各种数据结构,如列表、队列、集合和映射,使得在处理数据时具有更高的灵活性和效率。在众多的集合类中,`TreeMap`(K,V)是一个有序的Key-...
Java集合框架是Java编程语言中用于表示和操作集合类型的核心组件。这个框架提供了一种统一的体系结构,使得处理不同类型的集合变得更加高效和灵活。本章主要介绍了Java集合框架的基本内容、接口结构以及常用算法。 ...
在Java编程语言中,集合框架是处理对象数组的核心部分,而迭代器设计模式则是访问集合元素的主要机制。本文将深入探讨Java中的迭代器模式及其在集合框架中的应用。 迭代器模式是一种行为设计模式,它提供了一种方法...
Java集合框架由Collection和Map两大父接口统领。Collection接口是List、Set和Queue的父接口,用于存储单一数据类型的集合;Map接口用于存储键值对集合,由不同的实现类支持不同的访问机制和顺序特性。 List接口是...
`TreeMap`是Java集合框架的一部分,它实现了`NavigableMap`接口,提供了一种基于红黑树算法的有序映射服务。 描述"A TreeMap for you to examine and analyze"提示我们,这个压缩包可能包含有关`TreeMap`的详细资料...
它是Java集合框架的一部分,用于存储不重复的元素集合。 2. **Map接口**:Map接口存储键值对,其核心在于键(key)是唯一的,值(value)可以重复。Map接口中最常用的是HashMap和TreeMap。HashMap底层基于散列机制...
Java集合框架是Java编程语言中的核心部分,它为组织和管理对象提供了强大的工具。这份"java基础之集合面试题共4页.pdf.zip"文件显然包含了关于Java集合框架的一些常见面试问题,可能是为了帮助求职者准备面试或者...
### Java 6 Collection Framework 新特性概览 ...以上就是Java 6 Collection Framework中新特性的详细介绍,这些新特性和改进极大地增强了Java集合框架的功能性和灵活性,为开发者提供了更多的选择和便利。
在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,它提供了一种高效管理对象的方式。本项目"java_collection_source_code_analyze"专注于对Java集合框架的源代码进行深入分析,帮助开发者理解其内部...
Java集合框架是Java编程语言中的一个核心特性,它为数据存储和操作提供了强大的支持。"java-collection-jajal"很可能是一个项目或者库,专注于Java集合的实现和扩展,旨在提供更高效、易用的工具。虽然没有具体项目...
ConcurrentMap是Java并发包中的一种接口,它扩展了Java集合框架中的Map接口,提供了线程安全的并发操作。相比普通的HashMap,ConcurrentMap允许在多线程环境下并发地读写而不需外部同步。常见的实现类有: - ...
在Java编程语言中,集合框架是非常重要的一部分,它提供了存储和操作对象的高效方式。面试中,面试官经常考察候选者对于Java集合的理解,特别是集合的特性、性能以及线程安全方面的问题。以下是对Java集合相关知识点...
Java还提供了多种与集合框架紧密相关的并发集合类,这些类如ConcurrentHashMap、ConcurrentSkipListMap、PriorityBlockingQueue等,都是线程安全的集合实现,能够在多线程环境中安全使用。 总之,Java集合框架不仅...
7. **集合框架的高级特性**:包括ConcurrentSkipListMap、TreeSet等高级集合类,以及Lambda表达式和Stream API的使用。 8. **JavaFX**:对于图形用户界面(GUI)编程,介绍了JavaFX框架的使用,以及如何创建桌面...
在Java编程语言中,`Map`接口是集合框架的一部分,它提供了一种存储键值对数据结构的方法。Map不同于Collection接口,因为Map关注的是键值对的映射关系,而Collection则只处理单一元素的集合。下面我们将详细介绍Map...
- `ConcurrentSkipListMap`和`ConcurrentSkipListSet`:跳表实现的并发集合,支持高效并发的查找、插入和删除操作。 4. **原子类(Atomic Classes)** - `AtomicInteger`、`AtomicLong`等原子类提供了一种在不...
2. **集合框架**:在1.6.0中,Java集合框架已经相当完善,包括`List`、`Set`、`Map`接口及其实现类,如`ArrayList`、`HashSet`、`HashMap`。这个版本引入了`LinkedBlockingQueue`和`ConcurrentSkipListMap`等并发...
3. **集合框架**:Java 2的集合框架是其重要特性之一,包括List、Set、Map接口及其实现类,如ArrayList、LinkedList、HashSet、HashMap等。此外,还有高级集合如Queue、Deque和Tree结构,如PriorityQueue、...
- **并发工具的增强**:`ConcurrentHashMap`和`ConcurrentSkipListMap`等并发集合类的性能得到提升。 - **改进的Javadoc**:Javadoc工具现在支持HTML5元素和标签,输出文档更加美观。 - **新的编译器选项**:如`-...