映射Map
HashMap在7和8之间的变化:
- 7采用数组+单链表,JDK8之后,在链表长度达到8且总元素数量大于64之后会转变为红黑树,链表长度缩短到6之后会重新变为链表
- 7扩容时需要重新计算哈希值和索引位置,8并不重新计算哈希值,巧妙地采用和扩容后容量进行&操作来计算新的索引位置。
- 7插入元素到单链表中采用头插入法,8采用的是尾插入法,尽管尾插法需要遍历整个链表,但却能防止并发扩容时出现环。
存数据步骤:
- 计算哈希值
- 根据哈希值取模计算下标
- 尾插法存入链表(key已存在就覆盖value)
扩容步骤:
- 负载因子默认为0.75,防止大量发生CPU cache miss
- 初始容量为16,初始化哈希表时可以指定容量,但会向上取整到2^n,例如:new HashMap(519)的实际容量为1024
- 当数组负载大于复杂因子时就扩容到当前的2倍
HashMap
HashTable:使用synchronized关键字修饰方法,可以实现并发控制,但是效率较差;读数据时加共享锁即可,不必加大锁
ConcurrentHashMap:分割为大量segment处理,
ConcurrentSkipListMap:跳表,需要有序链表,无锁实现,用CAS;value不能为空;本质是建立索引,索引过多的情况下就建立索引的索引,通过多级索引,空间换时间;在redis和leveldb中有所应用;时间复杂度O(logn),空间复杂度O(n)
列表List
ArrayList:不能在遍历的同时删除元素,但可以借助Iterator实现;不保证并发安全
J.U.C包中提供了CopyOnWriteArrayList:读数据无锁;写数据时先加锁,然后拷贝要修改的数据,再在副本中修改数据,最后用修改后的副本替换原始数据;优点是并发安全;缺点是需要额外的内存占用,并且不保证可见性
集合Set
hashset:基于hashmap实现,非线程安全
CopyOnWriteArraySet:基于CopyOnWriteArrayList实现,线程安全
ConcurrentSkipListSet:基于ConcurrentSkipListMap实现,线程安全,有序,查询快
队列Queue
会抛异常的方法:add,remove,element
根据返回值自行判断队列状态的方法:offer,poll,peek
会阻塞的方法:put,take
优先级队列PriorityQueue:自动对输入的数据排序,并非先进先出,可以自行制定比较规则
延时队列DelayQueue:基于优先级队列实现,放入的元素在到达延时时间后才可以被使用;是用于实现ScheduledThreadPoolExecutor的核心数据结构
此外还有LinkedBlockingQueue、ConcurrentLinkedQueue
线程安全级别
不可变的:String,Long,BigInteger 无条件的线程安全:类的实例是可变的,但是类内部有足够的同步机制,例如:Random,ConcurrentHashMap 有条件的线程安全: 非线程安全: 线程对立的:
BIO与NIO
阻塞IO:资源不可用时,IO请求一直阻塞,直到反馈结果或超时
非阻塞IO:资源不可用时,IO请求直接反馈不可用
同步IO:应用阻塞在发送或接受数据的状态,直到数据成功传输或返回失败
异步IO:应用发送或接收数据后立刻返回,实际处理过程为异步
阻塞和非阻塞形容的是获取资源的方式;同步或异步描述的是程序如何处理资源的逻辑设计;两两组合一共有四种方式
NIO是JDK4之后引入的系统级IO操作API,用于替代原始IO/BIO,网络编程中的NIO更强调的是non-blocking
NIO的三大组件:
- Buffer缓冲区
- Channel通道
- Selector选择器