
HashMap與HashTable的差別
1.HashMap是非線程安全的,HashTable是線程安全的
2.HashMap的鍵和值都可以為null,HashTable則不行
3.線程安全問題,是以HashMap的效率比HashTable高
ArrayList和LinkList的比較
ArrayList和LinkedList都不是線程安全的,小并發量的情況下可以使用Vector,若并發量很多,且讀多寫少可以考慮使用CopyOnWriteArrayList。
因為CopyOnWriteArrayList底層使用ReentrantLock鎖,比使用synchronized關鍵字的Vector能更好的處理鎖競争的問題。
TreeSet, LinkedHashSet and HashSet 的差別
TreeSet的主要功能用于排序,它是無序的(插入順序)
LinkedHashSet的主要功能用于保證FIFO即有序的集合(先進先出)
HashSet隻是通用的存儲資料的集合
共同點
三者都不是線程安全的,如果要使用線程安全可以collections.synchronizedSet()
不同點
HashSet插入資料最快,其次LinkHashSet,最慢的是TreeSet因為内部實作排序
HashSet不保證有序,LinkHashSet保證FIFO即按插入順序排序,TreeSet安裝内部實作排序,也可以自定義排序規則
HashSet和LinkHashSet允許存在null資料,但是TreeSet中插入null資料時會報NullPointerException
TreeSet有兩種排序方式
- 自然排序
- 比較器排序
public class Student implements Comparable<Student>{
@Override
public int compareTo(Student s) {
public class MyComparator implements Comparator<Student> {
@Override
public int compare(Student s1,Student s2) {
TreeMap在添加、删除、定位映射關系上,性能比HashMap要差。适用于有序集合。
由于Set集合是唯一性的,由HashSet類實作的Set集合的優點是能夠快速定位集合中的元素。HashSet類需要重新實作equals()方法和hashCode()方法。
Queue和Deque接口繼承Collection接口,實作FIFO(先進先出)的集合。二者的差別在于,Queue隻能在隊尾入隊,隊頭出隊,而Deque接口則在隊頭和隊尾都可以執行出/入隊操作
Queue接口常用方法:
add(E)/offer(E):入隊,即向隊尾追加元素,二者的差別在于如果隊列是有界的,add方法在隊列已滿的情況下會抛出IllegalStateException,而offer方法隻會傳回false
remove()/poll():出隊,即從隊頭移除1個元素,二者的差別在于如果隊列是空的,remove方法會抛出NoSuchElementException,而poll隻會傳回null
element()/peek():檢視隊頭元素,二者的差別在于如果隊列是空的,element方法會抛出NoSuchElementException,而peek隻會傳回null
Deque接口常用方法:
addFirst(E) / addLast(E) / offerFirst(E) / offerLast(E)
removeFirst() / removeLast() / pollFirst() / pollLast()
getFirst() / getLast() / peekFirst() / peekLast()
removeFirstOccurrence(Object) / removeLastOccurrence(Object)
Queue接口的常用實作類:
ConcurrentLinkedQueue
ConcurrentLinkedQueue是基于連結清單實作的隊列,隊列中每個Node擁有到下一個Node的引用:
private static class Node {
volatile E item;
volatile Node<E> next;
}
由于Node類的成員都是volatile的,是以ConcurrentLinkedQueue自然是線程安全的。能夠保證入隊和出隊操作的原子性和一緻性,但在周遊和size()操作時隻能保證資料的弱一緻性。
LinkedBlockingQueue
與ConcurrentLinkedQueue不同,LinkedBlocklingQueue是一種無界的阻塞隊列。所謂阻塞隊列,就是在入隊時如果隊列已滿,線程會被阻塞,直到隊列有空間供入隊再傳回;同時在出隊時,如果隊列已空,線程也會被阻塞,直到隊列中有元素供出隊時再傳回。LinkedBlocklingQueue同樣基于連結清單實作,其出隊和入隊操作都會使用ReentrantLock進行加鎖。是以本身是線程安全的,但同樣的,隻能保證入隊和出隊操作的原子性和一緻性,在周遊時隻能保證資料的弱一緻性。
ArrayBlockingQueue
ArrayBlockingQueue是一種有界的阻塞隊列,基于數組實作。其同步阻塞機制的實作與LinkedBlocklingQueue基本一緻,差別僅在于前者的生産和消費使用同一個鎖,後者的生産和消費使用分離的兩個鎖。
ConcurrentLinkedQueue vsLinkedBlocklingQueue vs ArrayBlockingQueue
ConcurrentLinkedQueue是非阻塞隊列,其他兩者為阻塞隊列
三者都是線程安全的
LinkedBlocklingQueue是無界的,适合實作不限長度的隊列, ArrayBlockingQueue适合實作定長的隊列
SynchronousQueue
SynchronousQueue算是JDK實作的隊列中比較奇葩的一個,它不能儲存任何元素,size永遠是0,peek()永遠傳回null。向其中插入元素的線程會阻塞,直到有另一個線程将這個元素取走,反之從其中取元素的線程也會阻塞,直到有另一個線程插入元素。
這種實作機制非常适合傳遞性的場景。也就是說如果生産者線程需要及時确認到自己生産的任務已經被消費者線程取走後才能執行後續邏輯的場景下,适合使用SynchronousQueue。
PriorityQueue & PriorityBlockingQueue
這兩種Queue并不是FIFO隊列,而是根據元素的優先級進行排序,保證最小的元素最先出隊,也可以在構造隊列時傳入Comparator執行個體,這樣PriorityQueue就會按照Comparator執行個體的要求對元素進行排序。
PriorityQueue是非阻塞隊列,也不是線程安全的,PriorityBlockingQueue是阻塞隊列,同時也是線程安全的。
Deque 的實作類包括LinkedList(前文已描述過)、ConcurrentLinkedDeque、LinkedBlockingDeque,其實作機制與前文所述的ConcurrentLinkedQueue和LinkedBlockingQueue非常類似,此處不再贅述