图学java基础篇之集合
(本文部分图片引用自其他博客,最后有链接,侵删。由于笔记使用markdown记录,格式可能不是太好看,见谅)
集合结构
红字为java.util包下的,绿字为concurrent包下扩展的与并发相关的类
List
ArrayList
功能:有序非线程安全列表
要点:
- 底层存储用Object数组
- 元素可为null
- 自动扩容至1.5倍
- 适合随机访问,不适合大量或频繁增删
LinkedList
功能:有序非线程安全列表
要点:
- 基于双向链表实现
- 元素可为null
- 同时实现了双端队列Deque,支持队列、堆栈操作
- 适合增删,顺序访问,不适合随机访问
Vector
功能:有序线程安全列表
要点:
- 功能和ArrayList一样,只有线程安全区别,效率较ArrayList低
- 实际上算是老版本的List,除了线程安全的情况下不用
Stack
功能:基于Vector实现的堆栈
要点:
- 线程安全
- 后进先出(LIFO)1
CopyOnWriteArrayList
功能:快照版本的ArrayList,修改操作通过复制一份数组操作
要点:
- 线程安全
- 任何修改都会在拷贝的新副本上进行
- 修改操作通过ReentrantLock同步
- 迭代器只能访问,不能修改,且不会因为遍历过程中修改而抛异常
实现线程安全List的方法
- 使用synchronized:对List操作是进行同步,需要自己控制
- 使用Vector:效率低,已经较少使用了
- 使用CopyOnWriteArrayList,前边已经介绍了,这个只能在量小读多写少的场景下用,且性能很差,一般不要用
- 使用Collections.synchronizedList():工具类提供的一个比较简便的方法,可以直接创建一个线程安全的list,建议使用。其原理是对ArrayList进行包装,通过一个对象锁来控制并发,需要注意的是要弄清楚对象锁锁的是哪个对象。
Map
HashMap
功能:
要点:key-value的map,存储位置根据key的hash值确定
- 非线程安全
- 底层使用Entry<K, V>数组table
- 冲突使用链存储
- table长度为2^n,这样结合hash算法有利于均匀分布
- 当发生冲突时,新元素会插入到链首
- 每次table容量变化时,需要重新rehash
- 键值均可为null
HashTable
功能:key-value的map,存储位置根据key的hash值确定,与Hash的算法不同之处是,其位置直接通过hash(key)%table.length计算(HashMap使用h&(length – 1)计算,效率更高,才外还有一些细节不同,可自行参看源码)
要点:
- 线程安全
- 继承自Dictionary
- 底层使用Entry<K, V>数组table
- 冲突使用链存储
- table长度为2^n,这样结合hash算法有利于均匀分布
- 当发生冲突时,新元素会插入到链首
- 每次table容量变化时,需要重新rehash
- 键值不能为空
TreeMap
功能:基于红黑树实现的有序集合
要点:
- 非线程安全
- 底层为一个棵红黑树
- 继承NavigableMap,主要实现了SortMap,因此是有序的
- 增删改查都可参考红黑树操作
ConcurrentHashMap
功能:线程安全的HashMap,属于java.util.concurrent下的拓展类
要点:
- 线程安全
- 底层实现是一个Segment<K, V>数组,Segment内部通过一个HashEntry<K, V>数组存储元素数据,同时Segment继承了ReentrantLock,直接通过本身的锁对改段数据操作同步
- 从底层结构可以发现,其修改时不会对整个集合加锁,而是对段加锁,因此允许同时修改多个段,效率更高
- 继承NavigableMap,主要实现了SortMap,因此是有序的
- Segment的划分是通过key的hashCode计算
ConcurrentSkipListMap
功能:线程安全的有序Map,是通过一个叫做跳表的数据结构实现
要点:
- 线程安全
- 底层实现是一个多层链表,每层元素都有序,每低一层都包含上一层的元素,最底层包含所有元素。这样设计的巧妙之处是从上层逐层查找时,能够快速定位元素区间。思想上有点像折半查找,不过是把每次折半的中间值分层存了起来。同时链表结构是修改操作同样高效
- key是有序的
- 空间换时间,效率很高,但是空间占用也很厉害
Map的用法
- 非线程安全情景基本上都用HashMap
- 有序用TreeMap
- 线程安全优先ConcurrentHashMap
- ConcurrentHashMap和ConcurrentSkipListMap的优劣主要在于并发量,并发量不高时前者效率高,并发量很大时可以考虑后者
Set
HashSet
功能: 就是一个value均为同一个PRESENT对象的HashMap
要点:
- 非线程安全
- 底层为一个HashMap,其所有元素value值是一个Object类型的静态常量
- 其他参考HashMap
TreeSet
功能: 同TreeMap
要点:
- 非线程安全
- 底层为一个TreeMap,其所有元素value值是一个Object类型的静态常量
- 其他参考TreeMap
ConcurrentSkipListSet
功能: 同ConcurrentSkipListMap
CopyOnWriteArraySet
功能: 同ConcurrentSkipListMap
要点:
- 需要注意的是底层实现是通过CopyOnWriteArrayList,而非HashMap
- 使用场景与CopyOnWriteArrayList一样
Queue
Queue实现了队列操作,是基本集合的一个扩充,特点是提供了队列操作offer、poll和peek,主要分为两类,一类只支持单端操作,常见的如PriorityQueue,另一类为双端队列,可实现堆栈操作,均实现Deque。需注意的是队列也提供了add和remove,但应避免使用。
PriorityQueue
功能:如其名,优先级队列,可根据Comparator实现优先级排列
要点:
- 非线程安全
- 底层为一个Object数组
- 不提供Comparator时按照元素自然顺序
ArrayDeque
功能:如其名,优先级队列,可根据Comparator实现优先级排列
要点:
- 非线程安全
- 底层为一个E[]数组,同时提供head和tail记录存储数据的首位位置
- 由于使用数组不是链表,速度比LinkedList更快
LinkedBlockingDeque
功能:阻塞队列,支持支持FIFO和FILO
要点:
- 线程安全
- 底层为一个链表,通过一个ReentrantLock锁控制并发
- 可指定容量,实现阻塞,队满时插入阻塞,队空时读取阻塞,不指定则取最大整数
- 注意take在空时不阻塞直接返回失败,而poll则会阻塞
- 可指定元素超时时间
LinkedBlockingQueue
功能:阻塞队列,和LinkedBlockingDeque基本一样,不过支持队列操作
PriorityBlockingQueue
功能:优先级阻塞队列,直接看名字,不解释了
SynchronousQueue
功能:阻塞队列,特殊之处在于其不存储元素,一个元素入队之后必须出队,否则阻塞,可以理解为1个元素的阻塞队列
LinkedTransferQueue
功能:LinkedBlockingQueue和SynchronousQueue的结合体,特点是如果一个元素入队过程中发现又出队请求,则直接返回,不会再插入链表中
要点:
- 注意其并发并非通过ReentrantLock,而是通过LockSupport工具类实现
DelayQueue
功能:延迟队列,只有达到指定时间的元素才能出队
要点:
- 底层实现是一个PriorityQueue,通过ReentrantLock控制并发
- 可以理解为一个以入队时间-延迟时间为优先级的队列
一些使用上的浅见
- 从上边的总结可以看出来java对于集合的实现非常完善,几乎所有场景都有对应的类。因此我们应该避免重复造轮子,在合适的场景下使用合适的集合不仅省力,而且更可靠
- 能简则不繁,其实多数情况下我们使用基本的几个类就够了,复杂的实现一般用于底层框架_(如JDK以及一些常用框架中就用到了不少并发的实现,但其场景都十分鲜明)_。如果平时写也想上层逻辑时使用了负责的集合类,往往我们需要认真考虑下真的有没有必要,或者这部分是不是可以抽象为一个通用的组件,这算是个很有用的代码架构技巧吧。
- 无论怎么用,理解至上。几个基本类之所以用的顺手是因为我们熟悉其特性,而对于复杂的集合类一定要理解其特性,否则很容易踩坑。集合部分算是JDK中最容易理解的代码了,花一会儿时间而保证优质代码还是很值的。
备注
一些参考博客 (都是很优秀的博客,若个人看源码吃力,可以参考着这些博客来看)
http://cmsblogs.com/?cat=5
http://my.oschina.net/lifany/blog/191294
http://blog.csdn.net/guangcigeyun/article/details/8278349
http://www.cnblogs.com/skywang12345/p/3503480.html
http://www.infoq.com/cn/articles/java-blocking-queue/
http://my.oschina.net/readjava/blog/282882
http://hyxw5890.iteye.com/blog/1578597
以上xmind图源文件以及该系列相关文件都将同步至github,敬请关注
图学java基础篇之集合的更多相关文章
- 图学java基础篇之集合工具
两个工具类 java.utils下又两个集合相关_(准确来说其中一个是数组的)_的工具类:Arrays和Collections,其中提供了很多针对集合的操作,其中涵盖了一下几个方面: 拷贝.填充.反转 ...
- 图学java基础篇之并发
概述 并发处理本身就是编程开发重点之一,同时内容也很繁杂,从底层指令处理到上层应用开发都要涉及,也是最容易出问题的地方.这块知识也是评价一个开发人员水平的重要指标,本人自认为现在也只是学其皮毛,因此本 ...
- 图学java基础篇之IO
java io体系 如图可以看出,java的io按照包来划分的话可以分为三大块:io.nio.aio,但是从使用角度来看,这三块其实揉杂在一起的,下边我们先来概述下这三块: io:主要包含字符流和字节 ...
- Java 基础篇之集合
List 集合 List 集合中元素有序.可重复,集合中每个元素都有其对应的索引顺序. List 判断两个对象相等,只要通过 equals 方法比较返回 true 即可. 看个例子: public c ...
- java基础篇 之 集合概述(List)
list,有序集合,元素可重复 LinkedList:底层用链表实现,查找慢,增删快.为什么?? ArrayList:底层用数组实现,查找看,增删慢.为什么?? Vector:跟ArrayList一样 ...
- 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇
Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...
- Java基础篇(JVM)——类加载机制
这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
- 小白—职场之Java基础篇
java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...
- java基础篇---I/O技术
java基础篇---I/O技术 对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...
随机推荐
- JSTL,JQuery,Ajax,Json
JSTL 的定义 1 JSP 标准标签库 (JavaServerPage Standard Tag Library) 2 JSTL 通常会与EL 表达式合作实现JSP页面的编码 JSTL 的 ...
- 移植mavlink到stm32详细教程,后面附快速移植方法
一:准备材料: mavlink源码 stm32串口程序 1.mavlink源码: a.进入mavlink官网(http://qgroundcontrol.org/mavlink/s ...
- 谷歌插件 JSON-Handle
JSON-Handle http://jsonhandle.sinaapp.com/ 点击下载 插件下载后,在浏览器输入:chrome://extensions/ 将下载后的文件拖入 chrome浏览 ...
- CF1174D Ehab and the Expected XOR Problem
思路: 使用前缀和技巧进行问题转化:原数组的任意子串的异或值不能等于0或x,可以转化成前缀异或数组的任意两个元素的异或值不能等于0或x. 实现: #include <bits/stdc++.h& ...
- HDU 2602 Bone Collector骨头收藏者(01背包)
题意:收藏骨头. 思路: 常规的01背包. #include <iostream> #define N 1005 using namespace std; int volume[N]; / ...
- spring-autowire机制
在xml配置文件中,autowire有5种类型,可以在<bean/>元素中使用autowire属性指定 模式 说明 no ...
- 如何解决EXCEL中的科学计数法
EXCEL虽然能够有效的处理数据,尤其是数字的计算.但是,在单元格中输入数字的时候,很多时候都会受到科学计算法的困扰. 当单元格中输入的数字,超过11位时,就会自动变成科学计数法.无论您怎么调整列的宽 ...
- NOIP2018赛前停课集训记——最后的刷板子计划
前言 再过两天就\(NOIP2018\)了. 于是,我决定不做其他题目,开始一心一意刷板子了. 这篇博客记录的就是我的刷板子计划. [洛谷3383][模板]线性筛素数 这种普及-的题目我还写挂了两次( ...
- 从暴力匹配到KMP算法
前言 现在有两个字符串:\(s1\)和\(s2\),现在要你输出\(s2\)在\(s1\)当中每一次出现的位置,你会怎么做? 暴力匹配算法 基本思路 用两个指针分别指向当前匹配到的位置,并对当前状态进 ...
- 配置Python环境变量
虽然是老问题了,现在安装都自动配置环境变量. 这里,我是在VS2017中安装的Python3.6,但是没有自动配置好环境变量. 配置Python环境变量 打开[此电脑]—[属性]—[高级系统设置]—[ ...