寧國建設(shè)投資有限公司網(wǎng)站制作網(wǎng)站要花多少錢
文章目錄
- 1. java中 怎么確保一個集合不能被修改
- 2. 隊列和棧是什么 有什么區(qū)別
- 3. Java8開始的ConcurrentHashMap為什么舍棄了分段鎖
- 4. ConcurrentHashMap 和 Hashtable有什么區(qū)別
- 5. ReadWriteLock和StampeLock
1. java中 怎么確保一個集合不能被修改
Java 中可以使用 Collections 類的 unmodifiableXXX() 方法來確保一個集合不能被修改。其中,XXX 表示需要被轉(zhuǎn)換的集合類型,如 List、Set、Map 等。這些方法都返回指定集合的不可修改視圖。
例如,如果需要確保一個 List 集合不能被修改,可以使用以下方法:
List<String> list = new ArrayList<>();
// 往集合中添加元素List<String> unmodifiableList = Collections.unmodifiableList(list);
// 將 List 轉(zhuǎn)換為不可修改的視圖unmodifiableList.add("element"); // 會拋出 UnsupportedOperationException 異常
在上述代碼中,將一個 ArrayList 集合轉(zhuǎn)換為了不可修改的 List 視圖,并且嘗試向該視圖中添加新元素,此時會拋出 UnsupportedOperationException 異常。
需要注意的是,雖然通過 unmodifiableXXX() 方法返回的集合視圖可以防止對其進行新增、移除、修改等操作,但實際上集合元素本身并沒有被修改,因此如果原始集合發(fā)生了變化,集合視圖也會發(fā)生變化。因此,需要確保不會通過其他方式來修改原集合。
2. 隊列和棧是什么 有什么區(qū)別
隊列和棧都是常見的數(shù)據(jù)結(jié)構(gòu),其主要區(qū)別在于元素的插入和刪除順序不同。
隊列(Queue)是一種先進先出(First-In-First-Out,FIFO)的數(shù)據(jù)結(jié)構(gòu),類似于排隊等待服務(wù)。新元素總是被添加到隊列的尾部,而最先被添加的元素則總是位于隊列的頭部,也就是說,在隊列中,先進入隊列的元素也會先被處理。我們可以通過調(diào)用隊列的 offer() 方法向隊列的尾部添加元素,可以通過 poll() 方法從隊列的頭部刪除元素。
棧(Stack)是一種后進先出(Last-In-First-Out,LIFO)的數(shù)據(jù)結(jié)構(gòu),類似于疊羅漢。新元素總是被添加到棧的頂部,而最上面的元素則總是最后一個被處理,也就是說,在棧中,后進入的元素先被處理。我們可以通過調(diào)用棧的 push() 方法向棧的頂部添加元素,可以通過 pop() 方法從棧的頂部刪除元素。
另外,還有一個明顯的區(qū)別是隊列允許在任何時候插入和刪除元素,而棧只能在棧頂進行操作。此外,隊列通常有多種實現(xiàn)方式,如線性隊列、循環(huán)隊列和阻塞隊列等,每種實現(xiàn)方式都有其特點和適用場景;而棧的實現(xiàn)方式相對單一,大多數(shù)情況下只需要使用基本的數(shù)組或鏈表即可。
因此,當(dāng)需要處理一些按順序排列的元素集合時,需要先進先出的情況下就可以選擇使用隊列,如事件、消息等系統(tǒng);而對于需要依次處理棧頂?shù)那闆r,就可以使用棧,如表達式求值、函數(shù)調(diào)用等場景。
3. Java8開始的ConcurrentHashMap為什么舍棄了分段鎖
Java8開始的ConcurrentHashMap舍棄了分段鎖,主要是為了提高并發(fā)性能,這是因為在高并發(fā)下使用分段鎖會出現(xiàn)一些缺點。
首先,基于分段鎖的 ConcurrentHashMap 在處理高并發(fā)場景時會出現(xiàn)頻繁的競爭,每當(dāng)有新元素插入到集合中或者需要進行調(diào)整時,需要加鎖來保證原子性,在競爭激烈的情況下加鎖的開銷會顯得很大,阻礙整個系統(tǒng)的并發(fā)度。
其次,分段鎖本身也存在一些問題,例如需要維護多個鎖對象、容易產(chǎn)生死鎖等。雖然 JDK 7 中的 ConcurrentHashMap 引入了 Resize 的方式減少鎖的爭用,但在極端情況下仍然難以避免鎖引起的性能問題。
而在 Java8 中,ConcurrentHashMap 對底層數(shù)據(jù)結(jié)構(gòu)進行了重構(gòu),在實現(xiàn)上使用了 CAS 操作(Compare And Swap,比較并交換)和內(nèi)存屏障等機制,可以實現(xiàn)更高效的非阻塞并發(fā)操作。這種方式在多線程訪問時避免了鎖的開銷,在性能表現(xiàn)上能夠更好地支持高并發(fā)訪問,相對于分段鎖提供了更好的性能和可擴展性。
另外,在 Java8 中還引入了紅黑樹(Red-Black Tree)來代替鏈表,解決了 JDK 7 中并發(fā)度低且插入元素慢的問題,同時也讓每個線程擁有盡量少的鎖操作。這些改進與優(yōu)化,都大大提升了 ConcurrentHashMap 的效率和性能表現(xiàn)。
4. ConcurrentHashMap 和 Hashtable有什么區(qū)別
ConcurrentHashMap 和 Hashtable 都是線程安全的集合類,它們之間有以下幾點區(qū)別:
同步方式不同
Hashtable 通過 synchronized 關(guān)鍵字來實現(xiàn)同步,對整個對象進行鎖定,因此同一時刻只能有一個線程訪問該對象。而 ConcurrentHashMap 則通過分段鎖(JDK7及之前版本)或者無鎖算法(JDK8及以上版本)來實現(xiàn)同步,不同的線程可以同時訪問不同部分的數(shù)據(jù),因此并發(fā)度相對較高,性能也更好。
數(shù)據(jù)結(jié)構(gòu)不同
Hashtable 的數(shù)據(jù)結(jié)構(gòu)是數(shù)組加鏈表,當(dāng)一個鏈表中元素過多時,會產(chǎn)生嚴(yán)重的時間復(fù)雜度優(yōu)化問題。ConcurrentHashMap在 JDK8 版本后引入紅黑樹來解決這個問題。
空值和空鍵的處理不同
Hashtable 不允許 null 值和 null 鍵,如果以 null 作為 key 或 value 的話則會拋出 NullPointerException。而 ConcurrentHashMap 允許 null 值和 null 鍵。
迭代器的弱一致性策略不同
當(dāng)其他獨立線程改變了 ConcurrentHashMap 集合中的某個數(shù)值時,迭代器仍然可以繼續(xù)工作,而對于 Hashtable 則不能并發(fā)迭代,因為 iterators 在遍歷時要鎖定整個表格,所以將導(dǎo)致其他線程的所有訪問被阻塞。
ConcurrentHashMap 相對于 Hashtable 具有更好的并發(fā)性和可伸縮性,在高并發(fā)場景下,使用 ConcurrentHashMap 可以提供更優(yōu)秀的性能表現(xiàn)。
5. ReadWriteLock和StampeLock
ReadWriteLock和StampeLock都是Java并發(fā)包中提供的鎖機制,它們旨在優(yōu)化對于讀寫的并發(fā)操作。
ReadWriteLock
ReadWriteLock 接口定義了一個讀/寫鎖,它可以同時允許多個線程讀取共享資源,但只允許一個線程寫入共享資源,當(dāng)進行寫鎖定時,所有讀取線程和其他寫線程請求該鎖定將被阻塞。與一般的 Lock 實現(xiàn)不同的是,ReadWriteLock 允許多個線程同時訪問某個資源,以達到提高讀取操作性能的目的,在讀多寫少的場景下,使用 ReadWriteLock 可以有效減小鎖競爭,提高并發(fā)效率。
StampedLock
StampedLock 的實現(xiàn)基于樂觀鎖的思想,也是為了優(yōu)化讀操作執(zhí)行的速度而設(shè)計的一種鎖機制。由于讀取操作比寫操作更快,StampedLock 采用樂觀策略,當(dāng)進行讀取操作時,會嘗試樂觀獲取鎖,如果成功,則直接返回數(shù)據(jù),否則就退化成傳統(tǒng)的悲觀鎖來獲取鎖。StampedLock 中也有三種模式:寫模式、悲觀讀模式和樂觀讀模式。StampedLock 支持可重入,并提供了將悲觀鎖降級為樂觀鎖的方法。
在讀多寫少的場景下,使用讀寫鎖(ReadWriteLock)或 StampedLock 可以取得很好的性能提升效果。但需要注意的是,并不是所有的場景都適合使用讀寫鎖或 StampedLock,在存在大量寫操作并且這些寫操作耗時很長的情況下,這兩種鎖機制可能會導(dǎo)致讀操作被阻塞,進而影響系統(tǒng)的響應(yīng)時間。