1.Java中有哪些容器?
Java中的集合主要有两个接口,Map 和 Collection。
Collection接口的子接口有List, Set, Queue。
常见的实现类:
List: LinkedList, ArrayList
Set:HashSet, TreeSet(继承于SortedSet接口)
Queue: ArrayDeque(继承于Deque)
Map: HashMap, HashTable, TreeMap(根据键的大小排序), LinkedHashMap(根据插入顺序排序)
2.容器的线程安全问题
java.util包下的容器大部分是非线程安全的。
线程安全的实现类有HashTable, Vector,这两个类的内部方法是加了synchronized关键字,所以线程安全,但是性能不好,不建议使用。
Collections使用装饰器模式,提供了线程安全的包装类。
JAVA5之后提供juc包, 提供了线程安全的高性能实现类。主要包括三类:Blocking类,Concurrent类,CopyOnWrite类。
Concurrent:
内部很多操作使用 cas 优化,缩小锁粒度等操作
比如jdk1.7的ConcurrentHashMap,分段加锁。 jdk1.8 CAS + synchronized + Node + 红黑树。
ConcurrentLinkedQueue
Blocking :
实现基于锁
BlockingQueue
对队列两端设置dummy结点,然后开头和结尾设置两个锁。同时可以有一个生产者和一个消费者执行。
CopyOnWrite
CopyOnWrite 之类容器修改开销相对较重
CopyOnWrite写入时拷贝的思想, 更改操作会将底层数据拷贝一份,在拷贝上执行修改,不影响其他线程的读操作,读写分离。
CopyOnWriteArrayList
HashMap的并发死链问题
HashMap在扩容的时候创建一个新的数组,容量是原数组的两倍,然后把旧数组的元素重新计算索引位置放入新数组。jdk 1.7的时候发生hash冲突后新元素在链表的头部插入,而1.8之后改为在链表的尾部插入。1.7的情况下如果两个线程都对数组进行扩容可能会导致并发死链,产生链表的循环。
HashMap为什么用红黑树而不用B树?
红黑树在内存中比b树快, 查找的次数少。但是树的深度大,所以磁盘中不适合用红黑树。
TreeMap的底层原理
TreeMap底层是一个红黑树,根据键的自然顺序或者创建时提供的comparator进行排序
LinkedList和ArrayList的区别
插入,查找,空间有区别。
有哪些线程安全的List
Vector, Collections.SynchronizedList, CopyOnWriteList
ArrayList的底层数据结构
一个数组,初始容量为10, 每次扩容50%。 如果是以append的形式则速度还可以,但是根据index插入会很慢。
HashSet的数据结构
一个HashMap, 值为一个静态常量Object对象, PRESENT。
BlockingQueue中有哪些方法,为什么这样设计?
插入:add offer put
获取:remove poll take
抛异常 返回错误值(超时) 阻塞
TreeMap
TreeMap的实现是红黑树,要使用TreeMap, 元素必须实现comparable接口,或者在构造时传入一个comparator。TreeSet是通过TreeSet实现的。
PriorityQueue
优先级队列使用了一个优雅且高效的数据结构,称为堆(heap)。堆是一 个可以自我调整的二叉树,对树执行添加( add) 和删除(remore) 操作, 可以让最小的元素 移动到根,而不必花费时间对元素进行排序。
需要注意的是,add之后的节点对key进行修改不会对节点重排序。
LinkedHashMap
在一个HashMap的基础上,Entry内部有两个指针,形成双向链表。构造方法可以传入一个boolean accessOrder, true的话就是按照访问顺序排列,false是按照插入顺序排序。
要实现LRU缓存的话去覆写 boolean : removeEldestEntry, 这个方法在put的时候会被调用,返回true则会删除末尾节点。