基礎(chǔ)篇:Java集合,面試專用
本文轉(zhuǎn)載自微信公眾號(hào)「潛行前行」,作者 cscw。轉(zhuǎn)載本文請(qǐng)聯(lián)系潛行前行公眾號(hào)。
沒(méi)啥好說(shuō)的,在座的各位都是靚仔
- List 數(shù)組
- Vector 向量
- Stack 棧
- Map 映射字典
- Set 集合
- Queue 隊(duì)列
- Deque 雙向隊(duì)列
一般隊(duì)列的通用方法
操作方法 | 拋出異常 | 阻塞線程 | 返回特殊值 | 超時(shí)退出 |
---|---|---|---|---|
插入元素 | add(e) | put(e) | offer(e) | offer(e, timeout, unit) |
移除元素 | remove() | take() | poll() | pull(timeout, unit) |
檢查 | element() | peek() | 無(wú) | 無(wú) |
1.List 數(shù)組
- 元素按進(jìn)入先后有序保存,可重復(fù)
- List有兩種底層實(shí)現(xiàn),一種是數(shù)組,一種是鏈表,而鏈表的實(shí)現(xiàn)繼承了 Collection。數(shù)組和集合的區(qū)別:
- 數(shù)組大小是固定,集合是可變的
- 數(shù)組的元素可以基本類型也可以是引用類型,而集合只能是引用類型
ArrayList
- ArrayList底層是使用一個(gè)可動(dòng)態(tài)擴(kuò)容的數(shù)組,與普通數(shù)組的區(qū)別就是它是沒(méi)有固定大小的限制,可以添加或刪除元素
- 它的特點(diǎn)就是讀速度、更新快,增刪慢;內(nèi)存相鄰,根據(jù)Index讀取的時(shí)間復(fù)雜度是O(1);可以存儲(chǔ)重復(fù)元素,但線程不安全
- ArrayList 的擴(kuò)容機(jī)制
- //ArrayList openJDK 13
- private void add(E e, Object[] elementData, int s) {
- if (s == elementData.length) //放不下了
- elementData = grow(); // 擴(kuò)容
- elementData[s] = e;
- size = s + 1;
- }
- private Object[] grow() {
- return grow(size + 1);
- }
- private Object[] grow(int minCapacity) {
- int oldCapacity = elementData.length;
- if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
- int newCapacity = ArraysSupport.newLength(oldCapacity,
- minCapacity - oldCapacity, // minCapacity - oldCapacity == 1
- oldCapacity >> 1 ); // oldCapacity == 1/2 oldCapacity
- return elementData = Arrays.copyOf(elementData, newCapacity);
- } else {
- return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
- }
- }
- 如果當(dāng)前元素放不下,則擴(kuò)容至 1.5 倍,且大于等于 1
- // ArraysSupport.newLength
- public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
- //prefGrowth 是 oldLength 的 1/2,minGrowth 是 1。因此 newLength = 1.5 oldLength
- int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
- if (newLength - MAX_ARRAY_LENGTH <= 0) { // MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8
- return newLength;
- }
- return hugeLength(oldLength, minGrowth);
- }
LinkedList
- LinkedList的節(jié)點(diǎn)并不是存儲(chǔ)真實(shí)的數(shù)據(jù),而是存下數(shù)據(jù)的引用對(duì)象,而且節(jié)點(diǎn)之間使用引用相關(guān)聯(lián)
- LinkedList實(shí)現(xiàn)了Queue、Deque接口,可作為隊(duì)列使用;查找慢,增刪快,可以存儲(chǔ)重復(fù)元素,但線程不安全
- 使用 LinkedList 實(shí)現(xiàn)LRU
- public static class LRU<T> {
- //默認(rèn)的緩存大小
- private int CAPACITY = 0;
- //引用一個(gè)雙向鏈接表
- private LinkedList<T> list;
- //構(gòu)造函數(shù)
- public LRU(int capacity) {
- this.CAPACITY = capacity;
- list = new LinkedList();
- }
- //添加一個(gè)元素
- public synchronized void put(T object) {
- if (list != null && list.contains(object)) {
- list.remove(object);
- }
- removeLeastVisitElement();
- list.addFirst(object);
- }
- //移除最近訪問(wèn)次數(shù)最少的元素
- private void removeLeastVisitElement() {
- int size = list.size();
- //注意,這兒必須得是CAPACITY - 1否則所獲的size比原來(lái)大1
- if (size > (CAPACITY - 1)) {
- Object object = list.removeLast();
- }
- }
- //獲取第N個(gè)索引下面的元素
- public T get(int index) {
- return list.get(index);
- }
- }
- LinkedList 的 API
- public E getFirst() //獲取第一個(gè)元素
- public E getLast() //獲取最后一個(gè)元素
- public E removeFirst() // 移除第一個(gè)元素,并返回
- public E removeLast() // 移除最后一個(gè)元素,并返回
- public void addFirst(E e) //加入頭部
- public void addLast(E e) //加入尾部
- public void add(E e) //加入尾部
- public boolean contains(Object o) //是否包含 元素 o
- public E peek() //獲取頭部第一個(gè)元素
- public E element() // 獲取頭部第一個(gè)元素,不存在則報(bào)錯(cuò)
- public E poll() //獲取頭部第一個(gè)元素,并移除
- public boolean offer(E e) // 調(diào)用 add(E e)
- public boolean offerFirst(E e) // 調(diào)用 addFirst
- public boolean offerLast(E e) // 調(diào)用 addLast
- public void push(E e) //在頭部壓入一個(gè)元素
- public E pop() //彈出第一個(gè)元素,并移除。不存在則報(bào)錯(cuò)
- ArrayList 和 LinkedList 使用場(chǎng)景
- 頻繁訪問(wèn)列表中的某一個(gè)元素,或者需要在列表末尾進(jìn)行添加和刪除元素操作,用ArrayList
- 頻繁的在列表開(kāi)頭、中間、末尾等位置進(jìn)行添加和刪除元素操作,用LinkedList
Iterator 和 fast-fail、fail-safe機(jī)制
- Java Iterator(迭代器)不是一個(gè)集合,它是一種用于訪問(wèn)集合的方法,可用于迭代 List 和 Set 等集合,主要有hashNext(),next(),remove()三種方法
- fail-fast 是Java集合(Collection)的一種錯(cuò)誤機(jī)制。當(dāng)多個(gè)線程對(duì)同一個(gè)集合進(jìn)行修改結(jié)構(gòu)操作,使用集合的迭代器iterator,會(huì)首先檢測(cè)是否有對(duì)集合的并發(fā)修改,進(jìn)而產(chǎn)生ConcurrentModificationException 異常提示
- fail-safe:保證在對(duì)任何集合結(jié)構(gòu)的修改操作都基于 《復(fù)制-修改》 進(jìn)行的,即先copy一個(gè)新的集合對(duì)象,然后對(duì)新的集合對(duì)象進(jìn)行修改,最后將新的集合對(duì)象替換掉老的集合對(duì)象(老的集合對(duì)象的地址指向新的集合對(duì)象)。java.util.concurrent包下采用的是fail-safe機(jī)制。
- 缺點(diǎn)1-對(duì)集合的復(fù)制copy會(huì)產(chǎn)生大量的對(duì)象,造成內(nèi)存空間的浪費(fèi)。
- 缺點(diǎn)2-無(wú)法保證集合迭代過(guò)程中獲取的集合數(shù)據(jù)是最新的內(nèi)容
CopyOnWriteArrayList
- CopyOnWriteArrayList 的線程安全:CopyOnWriteArrayList 在寫的時(shí)候會(huì)加鎖,為了保證寫安全,會(huì)在寫操作時(shí)復(fù)制一個(gè)新數(shù)組來(lái)操作,然后覆蓋舊的數(shù)組;不會(huì)影響讀的性能
- public class CopyOnWriteArrayList<E>
- implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
- //可重入鎖
- final transient ReentrantLock lock = new ReentrantLock();
- //數(shù)組,僅通過(guò)get和set方法操作
- private transient volatile Object[] array;
- ....
- public boolean add(E e) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- Object[] elements = getArray();//拿到當(dāng)前數(shù)組
- int len = elements.length;//獲得長(zhǎng)度
- //拷貝當(dāng)前數(shù)組
- Object[] newElements = Arrays.copyOf(elements, len + 1);
- newElements[len] = e;
- setArray(newElements); //調(diào)用set方法將新數(shù)組設(shè)置為當(dāng)前數(shù)組
- return true;
- } finally {
- lock.unlock();//解鎖
- }
- }
- CopyOnWriteArrayList 的缺點(diǎn)
- CopyOnWrite 在進(jìn)行寫操作的時(shí)候,內(nèi)存里會(huì)同時(shí)駐扎兩個(gè)對(duì)象的內(nèi)存,導(dǎo)致內(nèi)存的浪費(fèi)
- CopyOnWrite 容器只能保證數(shù)據(jù)的最終一致性,不能保證數(shù)據(jù)的實(shí)時(shí)一致性。如果你希望寫入的的數(shù)據(jù),馬上能讀到,請(qǐng)不要使用CopyOnWrite容器,沒(méi)有阻塞等待的概念
- CopyOnWriteArrayList 和 Collections.synchronizedList 區(qū)別
- CopyOnWriteArrayList 的寫操作性能較差,而多線程的讀操作性能較好
- Collections.synchronizedList的寫操作性能比CopyOnWriteArrayList在多線程操作的情況下要好很多,而讀操作因?yàn)槭遣捎昧? synchronized關(guān)鍵字的方式,其讀操作性能并不如CopyOnWriteArrayList
線程安全的List
- A:使用 Vector;B:使用 Collections.synchronized() 返回線程安全的 List;C:使用 CopyOnWriteArrayList
List的API示例
- boolean contains(Object o) // 是否包含 o
- boolean isEmpty(); // 是否為空
- int size(); //集合元素
- Iterator<E> iterator(); // 返回迭代器
- Object[] toArray(); // 轉(zhuǎn)為 Object數(shù)組
- <T> T[] toArray(T[] a); // 轉(zhuǎn)為具體類型數(shù)組
- boolean add(E e); // 加入尾部
- boolean remove(Object o); // 移除 o
- boolean containsAll(Collection<?> c); //是否報(bào)考 集合 c
- boolean addAll(Collection<? extends E> c);// 合并 c
- boolean retainAll(Collection<?> c);//保留只存在集合 c 的元素
- void clear(); // 清除集合元素
- void sort(Comparator<? super E> c) //根據(jù) Comparator 排序
- E get(int index); // 根據(jù)下標(biāo)獲取 元素
- E set(int index, E element); // 設(shè)置第 index 的元素
- E remove(int index); // 移除 第 index 的元素
- <E> List<E> of(E e1.....) // jdk 9
- List<E> copyOf(Collection<? extends E> coll) // 復(fù)制
2.Vector(向量)
ArrayList 和 Vector、LinkedList 的區(qū)別
- Vector 相當(dāng)于是 ArrayList 線程安全的翻版
- Vector 繼承實(shí)現(xiàn)List 特點(diǎn): 底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,線程安全
Vector 的API示例
- boolean synchronized contains(Object o);
- boolean synchronized isEmpty();
- boolean synchronized containsAll(Collection<?> c);
- boolean addAll(Collection<? extends E> c);
- public synchronized boolean add(E e)
- public synchronized E get(int index);
- public synchronized E set(int index, E element);
- public synchronized E firstElement()
- public synchronized void removeElementAt(int index)
- public synchronized E lastElement()
- public synchronized void setElementAt(E obj, int index)
- public synchronized E remove(int index)
- public void clear()
- Iterator<E> iterator();
3.Stack(棧)
- Stack 是 Vector提供的一個(gè)子類,用于模擬"棧"這種數(shù)據(jù)結(jié)構(gòu)(LIFO后進(jìn)先出)
- 線程安全,允許 null 值
Stack 的API示例
- public E push(E item) //推入棧頂
- public synchronized E pop() // 彈出棧頂元素,不存在則報(bào)錯(cuò)
- public synchronized E peek() // 獲取棧頂元素,不移除
- public boolean empty() // 棧是否為空
- public synchronized int search(Object o) // 搜索元素
4.Map
- Map 用于保存具有映射關(guān)系的數(shù)據(jù),Map里保存著兩種映射的數(shù)據(jù):key和value,它們都可以使任何引用類型的數(shù)據(jù),但key不能重復(fù)。所以通過(guò)指定的key就可以取出對(duì)應(yīng)的value
- 請(qǐng)注意!!!Map 沒(méi)有繼承 Collection 接口
TreeMap(1.8JDK)
- 繼承 AbstractMap,TreeMap 是基于紅黑樹(shù)實(shí)現(xiàn),可保證在log(n)時(shí)間復(fù)雜度內(nèi)完成 containsKey,get,put 和 remove 操作,效率很高。(紅黑樹(shù)的原理這里不展開(kāi)講,后面會(huì)專門寫一篇)
- 另一方面,由于 TreeMap 基于紅黑樹(shù)實(shí)現(xiàn),因此 TreeMap 的鍵是有序的
HashMap
- HashMap 繼承AbstractMap類實(shí)現(xiàn)了Map,是一個(gè)散列表,它存儲(chǔ)的內(nèi)容是鍵值對(duì)(key-value)映射。HashMap 實(shí)現(xiàn)了 Map 接口,根據(jù)鍵的 HashCode 值存儲(chǔ)數(shù)據(jù),具有很快的訪問(wèn)速度,最多允許一條記錄的鍵為 null,不支持線程同步。HashMap 是無(wú)序的,即不會(huì)記錄插入的順序
- HashMap如何處理hash沖突,hash沖突的幾種解決方法
- 鏈地址法-如果存在 hash 碰撞,則創(chuàng)建一鏈表存儲(chǔ)相同的元素
- 開(kāi)放定址法容易導(dǎo)致 hash 碰撞,查詢慢
- 線性探查在散列的時(shí)候,如果當(dāng)前計(jì)算出的位置已經(jīng)被存儲(chǔ),那么就順序的向后查找,知道找到空位置或則是所有位置均不為空失敗
- 二次探查使用一個(gè)輔助散列函數(shù),使得后續(xù)的探查位置在前一個(gè)探查位置上加上一個(gè)偏移量,該偏移量以二次方的形式依賴于探查號(hào)i。二次探查的散列函數(shù)形式為:h(k,i)=(h'(k,i)+c1*i + c2 * i^2) mod m
- 雙重散列使用兩個(gè)輔助散列函數(shù)h1和h2,初始的散列位置是h1(k),后續(xù)的散列位置在此基礎(chǔ)上增加一個(gè)偏移量h2(k)*i mod m
- 開(kāi)放定址法
- 鏈地址法
- HashMap 底層實(shí)現(xiàn)是數(shù)組+鏈表+紅黑樹(shù)??諈⒌腍ashMap初始容量是16,默認(rèn)加載因子為0.75。取值0.75是因?yàn)?0.5 容易浪費(fèi)空間,取值 1 則需要填滿每一個(gè)桶,實(shí)際情況很難達(dá)到,會(huì)產(chǎn)生大量的哈希碰撞。因此取中間值
- HashMap 的容量一般是 2 的冪次方,可直接使用“位與”計(jì)算 hash 值,相對(duì)取模計(jì)算 hash 快
Hashtable
- 繼承于Dictionary,現(xiàn)在基本已被淘汰
- HashTable的操作幾乎和HashMap一致,主要的區(qū)別在于HashTable為了實(shí)現(xiàn)多線程安全,在幾乎所有的方法上都加上了synchronized鎖,而加鎖的結(jié)果就是HashTable操作的效率十分低下
- HashMap允許有一個(gè)鍵為null,允許多個(gè)值為null;但HashTable不允許鍵或值為null
- Hash映射:HashMap的hash算法通過(guò)非常規(guī)設(shè)計(jì),將底層table長(zhǎng)度設(shè)計(jì)為2的冪,使用位與運(yùn)算代替取模運(yùn)算,減少運(yùn)算消耗;而HashTable的hash算法首先使得hash值小于整型數(shù)最大值,再通過(guò)取模進(jìn)行散射運(yùn)算
LinkedHashMap
- LinkedHashMap的元素存取過(guò)程基本與HashMap基本類似,只是在細(xì)節(jié)實(shí)現(xiàn)上稍有不同。當(dāng)然,這是由LinkedHashMap本身的特性所決定的,因?yàn)樗~外維護(hù)了一個(gè)雙向鏈表用于保持迭代順序。此外,LinkedHashMap可以很好的支持LRU算法。HashMap和雙向鏈表合二為一即是LinkedHashMap
WeakHashMap
- WeakHashMap 也是一個(gè)散列表,它存儲(chǔ)的內(nèi)容也是鍵值對(duì)(key-value)映射,而且鍵和值都可以是 null
- WeakHashMap的鍵是“弱鍵”。在 WeakHashMap 中,當(dāng)某個(gè) key 不再被強(qiáng)引用使用時(shí),會(huì)被從WeakHashMap中被 JVM 自動(dòng)移除,然后它對(duì)應(yīng)的鍵值對(duì)也會(huì)被從WeakHashMap中移除。?JAVA引用類型和ThreadLocal
ConcurrentHashMap(1.8JDK)
- ConcurrentHashMap 是 HashMap 的多線程安全版本。它使用了細(xì)粒度鎖 和 cas 提高了在多線程環(huán)境的安全性和高并發(fā)
- 底層數(shù)據(jù)結(jié)構(gòu)是 數(shù)組 + 鏈表/紅黑樹(shù)(后面專門寫一篇介紹)
ConcurrentSkipListMap 了解一波
- ConcurrentSkipListMap 則是基于跳躍鏈表的實(shí)現(xiàn)的 map,使用了 cas 技術(shù)實(shí)現(xiàn)線程安全性,高并發(fā)
- ConcurrentSkipListMap 相比 ConcurrentHashMap 的優(yōu)點(diǎn)
- ConcurrentSkipListMap 的key是有序的。
- ConcurrentSkipListMap 支持更高的并發(fā)。ConcurrentSkipListMap的存取時(shí)間是log(N),和線程數(shù)幾乎無(wú)關(guān)。也就是說(shuō)在數(shù)據(jù)量一定的情況下,并發(fā)的線程越多,ConcurrentSkipListMap 越能體現(xiàn)出它的優(yōu)勢(shì)
NavigableMap 和 ConcurrentNavigableMap 操作 key 值的范圍區(qū)間
- TreeMap 實(shí)現(xiàn)了 NavigableMap 。ConcurrentNavigableMap 高并發(fā)線程安全版的 TreeMap
- NavigableMap 提供了針對(duì)給定搜索目標(biāo)返回最接近匹配項(xiàng)的導(dǎo)航方法。直接看API
- K lowerKey(K key) // 找到第一個(gè)比指定的key小的值
- K floorKey(K key) // 找到第一個(gè)比指定的key小于或等于的key
- K ceilingKey(K key) // 找到第一個(gè)大于或等于指定key的值
- K higherKey(K key) // 找到第一個(gè)大于指定key的值
- Map.Entry<K,V> firstEntry() // 獲取最小值
- Map.Entry<K,V> lastEntry() // 獲取最大值
- Map.Entry<K,V> pollFirstEntry() // 刪除最小的元素
- Map.Entry<K,V> pollLastEntry() // 刪除最大的元素
- NavigableMap<K,V> descendingMap() //返回一個(gè)倒序的Map
- // 返回值小于 toKey 的 NavigableMap
- NavigableMap<K,V> headMap(K toKey, boolean inclusive)
- // 返回值大于 fromKey 的 NavigableMap
- NavigableMap<K,V> tailMap(K fromKey, boolean inclusive)
- // 返回值小于 toKey 大于 的 fromKey NavigableMap
- NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
5.Set(集合)
- Set特點(diǎn):元素?zé)o放入順序,元素不可重復(fù),如果加入重復(fù)元素,會(huì)保留最先加入的對(duì)象。存取速度快
Set 的幾種實(shí)現(xiàn)子類和各自特點(diǎn)
- TreeSet:底層數(shù)據(jù)結(jié)構(gòu)采用二叉樹(shù)來(lái)實(shí)現(xiàn),元素唯一且已經(jīng)排好序;唯一性同樣需要重寫 hashCode 和 equals()方法,二叉樹(shù)結(jié)構(gòu)保證了元素的有序
- 根據(jù)構(gòu)造方法不同,分為自然排序(無(wú)參構(gòu)造)和比較器排序(有參構(gòu)造),自然排序要求元素必須實(shí)現(xiàn)Compareable接口,并重寫里面的compareTo()方法
- HashSet:是哈希表實(shí)現(xiàn)的,HashSet中的數(shù)據(jù)是無(wú)序的,可以放入 null,但只能放入一個(gè)null,兩者中的值都不能重復(fù),就如數(shù)據(jù)庫(kù)中唯一約束
- HashSet 是基于 HashMap 算法實(shí)現(xiàn)的,其性能通常都優(yōu)于TreeSet
- 為快速查找而設(shè)計(jì)的Set,我們通常都會(huì)用到HashSet,若需要排序的功能時(shí),才使用TreeSet
- LinkedHashSet:底層數(shù)據(jù)結(jié)構(gòu)采用鏈表和哈希表共同實(shí)現(xiàn),鏈表保證了元素的順序與存儲(chǔ)順序一致,哈希表保證了元素的唯一性,效率高。但線程不安全
ConcurrentSkipListSet
- 基于 ConcurrentSkipListMap 實(shí)現(xiàn)
CopyOnWriteArraySet
- 基于 CopyOnWriteArrayList 實(shí)現(xiàn)
BitSet
- BitSet是位操作的對(duì)象,值只有 0 或 1 即false和true,內(nèi)部維護(hù)了一個(gè)long數(shù)組,初始只有一個(gè)long,所以BitSet最小的size是64,當(dāng)隨著存儲(chǔ)的元素越來(lái)越多,BitSet內(nèi)部會(huì)動(dòng)態(tài)擴(kuò)充,最終內(nèi)部是由N個(gè)long來(lái)存儲(chǔ)
- 如統(tǒng)計(jì)40億個(gè)數(shù)據(jù)中沒(méi)有出現(xiàn)的數(shù)據(jù),將40億個(gè)不同數(shù)據(jù)進(jìn)行排序等。\
- 現(xiàn)在有1千萬(wàn)個(gè)隨機(jī)數(shù),隨機(jī)數(shù)的范圍在1到1億之間?,F(xiàn)在要求寫出一種算法,將1到1億之間沒(méi)有在隨機(jī)數(shù)中的數(shù)求出來(lái)
- void and(BitSet set) // 兩個(gè)BitSet 做與操作,結(jié)果并存入當(dāng)前 BitSet
- void andNot(BitSet set) // 兩個(gè)BitSet 與非操作
- void flip(int index) // 反轉(zhuǎn)某一個(gè)指定 index
- boolean intersects(BitSet bitSet) // 是否有交集
- int cardinality() //返回 true/1 的個(gè)數(shù)
- void clear() // 重置
- void clear(int startIndex, int endIndex) // startIndex~endIndex 重置
- int nextSetBit(int startIndex) //檢索在startIndex之后出現(xiàn)為1的第一位的索引
- int nextClearBit(int startIndex) //檢索在startIndex之后出現(xiàn)為0的第一位的索引
6.Queue(隊(duì)列)
- Queue的概念 隊(duì)列是一種特殊的線性表,只允許元素從隊(duì)列一端入隊(duì),而另一端出隊(duì)(獲取元素),就像我們平時(shí)排隊(duì)結(jié)算一樣(懂文明講禮貌不插隊(duì))。Queue 的數(shù)據(jù)結(jié)構(gòu)和 List 一樣,可以基于數(shù)組,鏈表實(shí)現(xiàn),隊(duì)列通常都是一端進(jìn)(offer),另一端出(poll),有序性
PriorityQueue
- PriorityQueue是按優(yōu)先級(jí)排序的隊(duì)列,也就是說(shuō) vip 可以插隊(duì)。優(yōu)先隊(duì)列要求使用 Java Comparable 和 Comparator 接口給對(duì)象排序,并且在排序時(shí)會(huì)按照優(yōu)先級(jí)處理其中的元素
- PriorityBlockingQueue 是線程安全的PriorityQueue
BlockingQueue
- BlockingQueue很好的解決了多線程中,如何高效安全“傳輸”數(shù)據(jù)的問(wèn)題。通過(guò)這些高效并且線程安全的隊(duì)列類,為我們快速搭建高質(zhì)量的多線程程序帶來(lái)極大的便利。常用于線程的任務(wù)隊(duì)列
DelayQueue
- DelayQueue是一個(gè)沒(méi)有邊界BlockingQueue實(shí)現(xiàn),加入元素必須實(shí)現(xiàn)Delayed接口。當(dāng)生產(chǎn)者線程調(diào)用put之類的方法加入元素時(shí),會(huì)觸發(fā) Delayed 接口中的compareTo方法進(jìn)行排序
- 消費(fèi)者線程查看隊(duì)列頭部的元素,注意是查看不是取出。然后調(diào)用元素的getDelay方法,如果此方法返回的值小0或者等于0,則消費(fèi)者線程會(huì)從隊(duì)列中取出此元素,并進(jìn)行處理。如果getDelay方法返回的值大于0,則消費(fèi)者線程阻塞到第一元素過(guò)期
Queue 的 API
- boolean add(E e); //加入隊(duì)列尾部
- boolean offer(E e); // 加入隊(duì)列尾部,并返回結(jié)果
- E remove(); //移除頭部元素
- E poll(); // 獲取頭部元素,并移除
- E element(); // 獲取頭部元素,不存在則報(bào)錯(cuò)
- E peek(); // 獲取頭部元素,不移除
7.Deque(雙向隊(duì)列)
- Deque接口代表一個(gè)"雙端隊(duì)列",雙端隊(duì)列可以同時(shí)從兩端來(lái)添加、刪除元素,因此Deque的實(shí)現(xiàn)類既可以當(dāng)成隊(duì)列使用、也可以當(dāng)成棧使用
- Deque 的子類 LinkedList,ArrayDeque,LinkedBlockingDeque
Deque的 API
- void addFirst(E e); //加入頭部
- void addLast(E e); //加入尾部
- boolean offerFirst(E e); //加入頭部,并返回結(jié)果
- boolean offerLast(E e); //加入尾部,并返回結(jié)果
- E removeFirst(); // 移除第一個(gè)元素
- E removeLast(); // 移除最后一個(gè)元素
- E getFirst(); //獲取第一個(gè)元素,不存在則報(bào)錯(cuò)
- E getLast(); //獲取最后一個(gè)元素,不存在則報(bào)錯(cuò)
- E pollFirst(); //獲取第一個(gè)元素,并移除
- E pollLast(); //獲取最后一個(gè)元素,并移除
- E peekFirst(); //獲取第一個(gè)元素
- E peekLast(); // 獲取最后一個(gè)元素
- void push(E e); //加入頭部
- E pop(); //彈出頭部元素
參考文章
java集合超詳解