網(wǎng)站宣傳視頻瑞金網(wǎng)絡(luò)推廣
Java 并發(fā)容器是一組用于在多線程環(huán)境下安全訪問和操作數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。它們提供了線程安全的集合和映射,使開發(fā)者能夠更輕松地處理并發(fā)編程問題。
一、Java并發(fā)容器
-
ConcurrentHashMap: 它是一個(gè)高效的并發(fā)哈希表,支持多線程并發(fā)操作而不需要顯式的同步。適用于高并發(fā)讀和寫操作的場(chǎng)景。
-
CopyOnWriteArrayList :這個(gè)容器支持在迭代期間進(jìn)行并發(fā)寫操作。當(dāng)需要在讀操作頻繁而寫操作較少的場(chǎng)景中使用。
-
ConcurrentLinkedQueue 和 ConcurrentLinkedDeque: 這些是非阻塞隊(duì)列實(shí)現(xiàn),適用于高吞吐量的并發(fā)隊(duì)列操作。通常用于任務(wù)調(diào)度、工作隊(duì)列等場(chǎng)景。
-
BlockingQueue: 它是一組阻塞隊(duì)列的接口,如 LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue 等。這些隊(duì)列提供了在隊(duì)列為空或滿時(shí)阻塞線程的能力,適用于生產(chǎn)者-消費(fèi)者問題和任務(wù)調(diào)度等。
-
Semaphore 和 CountDownLatch: 雖然不是容器,但它們是并發(fā)編程中常用的同步工具。
二、ConcurrentHashMap?
ConcurrentHashMap
是 Java 中的一個(gè)線程安全的哈希表(散列表)實(shí)現(xiàn),它允許多個(gè)線程同時(shí)讀取數(shù)據(jù),而不需要顯式的同步操作,并且支持高并發(fā)的讀和寫操作。ConcurrentHashMap
的主要特點(diǎn)包括:
-
并發(fā)讀取: 多個(gè)線程可以同時(shí)讀取數(shù)據(jù),不會(huì)被阻塞,這使得
ConcurrentHashMap
在讀多寫少的場(chǎng)景下非常高效。 -
分段鎖:
ConcurrentHashMap
內(nèi)部使用了分段鎖機(jī)制,將數(shù)據(jù)分成多個(gè)段(Segment),每個(gè)段上都有一個(gè)鎖,不同線程可以同時(shí)訪問不同段的數(shù)據(jù),從而提高并發(fā)性能。 -
線程安全寫入: 寫操作(如插入、更新、刪除)仍然是線程安全的,但它不會(huì)鎖住整個(gè)數(shù)據(jù)結(jié)構(gòu),而只鎖住相關(guān)的段,使得其他線程仍然可以訪問不同段的數(shù)據(jù)。
-
弱一致性:
ConcurrentHashMap
提供了一定程度的弱一致性,因?yàn)樗槐WC在某一時(shí)刻數(shù)據(jù)的完全一致性,但保證了線程的安全性。 -
擴(kuò)展性:
ConcurrentHashMap
具有較好的擴(kuò)展性,可以通過調(diào)整初始容量和負(fù)載因子來(lái)優(yōu)化性能。 -
迭代支持:
ConcurrentHashMap
提供了安全的迭代器,它可以在遍歷時(shí)支持并發(fā)寫操作。
? ? ?ConcurrentHashMap用法示例
import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample {public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();// 插入數(shù)據(jù)map.put("one", 1);map.put("two", 2);map.put("three", 3);// 獲取數(shù)據(jù)int value = map.get("two");System.out.println("Value for key 'two': " + value);// 刪除數(shù)據(jù)map.remove("three");// 迭代數(shù)據(jù)for (String key : map.keySet()) {int val = map.get(key);System.out.println(key + ": " + val);}}
}
雖然 ConcurrentHashMap
支持高并發(fā)讀取和寫入,但在一些特定情況下仍然需要考慮同步和競(jìng)態(tài)條件問題。
三、CopyOnWriteArrayList
CopyOnWriteArrayList
是 Java 集合框架中的一種線程安全的并發(fā)容器,它提供了一種特殊的并發(fā)策略,適用于讀多寫少的場(chǎng)景。與普通的 ArrayList
不同,CopyOnWriteArrayList
在寫操作時(shí)不對(duì)原有數(shù)據(jù)進(jìn)行修改,而是創(chuàng)建一個(gè)新的副本,這樣可以避免讀操作與寫操作之間的競(jìng)態(tài)條件,保證讀操作的線程安全。
主要特點(diǎn)和用途包括:
-
線程安全的讀取: 多個(gè)線程可以同時(shí)讀取數(shù)據(jù),而不需要顯式的同步操作。這使得
CopyOnWriteArrayList
在讀多寫少的場(chǎng)景下非常高效。 -
寫入時(shí)復(fù)制(Copy-On-Write): 寫入操作會(huì)創(chuàng)建一個(gè)新的副本,而不是修改原有數(shù)據(jù)。這確保了寫操作不會(huì)影響正在進(jìn)行的讀操作,保證了讀操作的一致性。原有的數(shù)據(jù)在寫入完成后會(huì)被廢棄。
-
高效的迭代:
CopyOnWriteArrayList
提供了安全的迭代器,可以在迭代集合時(shí)進(jìn)行并發(fā)寫操作,不會(huì)拋出ConcurrentModificationException
異常。 -
適用于不頻繁寫入的場(chǎng)景: 由于寫操作涉及復(fù)制數(shù)據(jù),因此
CopyOnWriteArrayList
適用于寫操作不頻繁、但讀操作較多的情況,如事件監(jiān)聽器列表、觀察者模式等。
?下面是一個(gè)簡(jiǎn)單示例,展示了如何使用 CopyOnWriteArrayList
:
import java.util.concurrent.CopyOnWriteArrayList;public class CopyOnWriteArrayListExample {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();// 插入數(shù)據(jù)list.add("one");list.add("two");list.add("three");// 獲取數(shù)據(jù)String value = list.get(1);System.out.println("Value at index 1: " + value);// 迭代數(shù)據(jù)for (String item : list) {System.out.println(item);}// 寫操作不影響正在進(jìn)行的讀操作list.add("four");// 迭代數(shù)據(jù)(包含新添加的元素)for (String item : list) {System.out.println(item);}}
}
四、BlockingQueue
BlockingQueue
是 Java 并發(fā)編程中的一個(gè)重要接口,它表示一種線程安全的阻塞隊(duì)列。阻塞隊(duì)列在多線程編程中非常有用,因?yàn)樗峁┝艘环N線程安全的方式來(lái)實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型和其他協(xié)作模式。
BlockingQueue
接口繼承自 Queue
接口,它定義了一組用于插入、刪除和檢查元素的方法,但與普通的隊(duì)列不同,BlockingQueue
的方法具有阻塞特性,這意味著當(dāng)隊(duì)列為空時(shí),從隊(duì)列中取元素的操作會(huì)被阻塞,直到有元素可用;當(dāng)隊(duì)列已滿時(shí),向隊(duì)列中插入元素的操作也會(huì)被阻塞,直到有空間可用。
常見的 BlockingQueue
實(shí)現(xiàn)包括:
-
LinkedBlockingQueue: 基于鏈表的阻塞隊(duì)列,可以設(shè)置容量,當(dāng)隊(duì)列為空或已滿時(shí),操作會(huì)被阻塞。
-
ArrayBlockingQueue: 基于數(shù)組的阻塞隊(duì)列,需要指定容量,當(dāng)隊(duì)列為空或已滿時(shí),操作會(huì)被阻塞。
-
PriorityBlockingQueue: 基于優(yōu)先級(jí)的阻塞隊(duì)列,元素會(huì)按照優(yōu)先級(jí)進(jìn)行排序,不需要容量限制。
-
DelayQueue: 用于存放實(shí)現(xiàn)了
Delayed
接口的元素,元素只能在延遲時(shí)間過后才能被取出。 -
LinkedTransferQueue: 支持多個(gè)生產(chǎn)者和消費(fèi)者的隊(duì)列,具有高吞吐量。
-
SynchronousQueue: 一種特殊的阻塞隊(duì)列,它沒有容量,用于直接傳遞數(shù)據(jù)的通信。
使用 BlockingQueue
可以輕松實(shí)現(xiàn)一些經(jīng)典的多線程協(xié)作模式,例如生產(chǎn)者-消費(fèi)者模型。以下是一個(gè)簡(jiǎn)單示例,演示了如何使用 LinkedBlockingQueue
實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型:
import java.util.concurrent.*;public class ProducerConsumerExample {public static void main(String[] args) {BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);// 生產(chǎn)者線程Thread producer = new Thread(() -> {try {for (int i = 1; i <= 10; i++) {queue.put(i);System.out.println("Produced: " + i);Thread.sleep(100);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});// 消費(fèi)者線程Thread consumer = new Thread(() -> {try {for (int i = 1; i <= 10; i++) {int value = queue.take();System.out.println("Consumed: " + value);Thread.sleep(200);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producer.start();consumer.start();}
}
在上述示例中,生產(chǎn)者線程不斷往隊(duì)列中放入數(shù)據(jù),而消費(fèi)者線程則不斷從隊(duì)列中取出數(shù)據(jù),它們通過阻塞隊(duì)列實(shí)現(xiàn)了線程間的協(xié)作。這種模型可以用于處理多個(gè)生產(chǎn)者和消費(fèi)者的情況,并確保線程安全。
BlockingQueue
是并發(fā)編程中的一個(gè)重要工具,可以簡(jiǎn)化線程之間的通信和同步,減少了開發(fā)者需要處理的低級(jí)細(xì)節(jié)。根據(jù)具體的需求,選擇合適的 BlockingQueue
實(shí)現(xiàn)非常重要。
五、Semaphore ?
Semaphore
是 Java 并發(fā)編程中的一個(gè)同步工具,用于控制同時(shí)訪問某個(gè)資源的線程數(shù)量。它允許多個(gè)線程并發(fā)訪問共享資源,但可以限制同時(shí)訪問的線程數(shù)目,從而實(shí)現(xiàn)資源的有序分配。
Semaphore
主要有兩個(gè)重要的操作:
-
acquire(): 當(dāng)一個(gè)線程希望獲取資源時(shí),它調(diào)用
acquire()
方法。如果有可用的資源,線程將獲得許可,并繼續(xù)執(zhí)行。如果沒有可用的資源,線程將被阻塞,直到有資源可用為止。 -
release(): 當(dāng)一個(gè)線程使用完資源時(shí),它調(diào)用
release()
方法來(lái)釋放資源。這會(huì)導(dǎo)致信號(hào)量的許可數(shù)增加,從而允許其他等待資源的線程獲得許可并繼續(xù)執(zhí)行。
Semaphore
可以用于以下一些典型的場(chǎng)景:
-
控制資源訪問數(shù)量: 限制同時(shí)訪問某個(gè)共享資源的線程數(shù)量,例如數(shù)據(jù)庫(kù)連接池的控制。
-
實(shí)現(xiàn)有界容器: 可以用
Semaphore
來(lái)實(shí)現(xiàn)有界的集合,例如有界隊(duì)列。 -
實(shí)現(xiàn)并發(fā)任務(wù)控制: 控制并發(fā)任務(wù)的數(shù)量,例如控制同時(shí)運(yùn)行的線程數(shù)量。
下面是一個(gè)簡(jiǎn)單示例,演示了如何使用 Semaphore
來(lái)控制同時(shí)執(zhí)行的線程數(shù)量:
?
import java.util.concurrent.Semaphore;public class SemaphoreExample {public static void main(String[] args) {// 創(chuàng)建一個(gè)Semaphore,限制最多同時(shí)有兩個(gè)線程訪問共享資源Semaphore semaphore = new Semaphore(2);// 創(chuàng)建多個(gè)線程for (int i = 1; i <= 5; i++) {Thread thread = new Thread(() -> {try {System.out.println(Thread.currentThread().getName() + " is waiting for a permit.");semaphore.acquire();System.out.println(Thread.currentThread().getName() + " has acquired a permit.");Thread.sleep(2000); // 模擬線程在共享資源上的操作} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {System.out.println(Thread.currentThread().getName() + " is releasing a permit.");semaphore.release();}});thread.start();}}
}
在上述示例中,我們創(chuàng)建了一個(gè) Semaphore
,并限制最多同時(shí)有兩個(gè)線程可以獲得許可。多個(gè)線程嘗試獲取許可,但只有兩個(gè)線程能夠同時(shí)執(zhí)行,其余的線程會(huì)被阻塞,直到有許可可用。
Semaphore
是一個(gè)非常有用的同步工具,可用于管理共享資源的并發(fā)訪問,控制線程的并發(fā)數(shù)量,以及其他需要有序控制的場(chǎng)景。
六、CountDownLatch
CountDownLatch
是 Java 并發(fā)編程中的一個(gè)同步工具類,它用于實(shí)現(xiàn)一種等待多個(gè)線程完成任務(wù)的場(chǎng)景。CountDownLatch
通過一個(gè)計(jì)數(shù)器來(lái)實(shí)現(xiàn),計(jì)數(shù)器的值初始化為一個(gè)正整數(shù),然后多個(gè)線程執(zhí)行任務(wù),每個(gè)任務(wù)執(zhí)行完畢后,計(jì)數(shù)器的值減一,當(dāng)計(jì)數(shù)器的值變?yōu)榱銜r(shí),等待的線程可以繼續(xù)執(zhí)行。
CountDownLatch
主要有兩個(gè)重要的方法:
-
countDown()
: 每個(gè)任務(wù)執(zhí)行完畢后調(diào)用這個(gè)方法來(lái)減小計(jì)數(shù)器的值。通常在任務(wù)的最后一步調(diào)用。 -
await()
: 等待計(jì)數(shù)器的值變?yōu)榱?#xff0c;一直阻塞當(dāng)前線程,直到計(jì)數(shù)器值為零才繼續(xù)執(zhí)行。
CountDownLatch
可以用于以下一些典型的場(chǎng)景:
-
多個(gè)線程協(xié)作完成任務(wù): 主線程等待多個(gè)子線程完成任務(wù)后再繼續(xù)執(zhí)行。
-
控制并發(fā)任務(wù)的開始: 多個(gè)線程等待某個(gè)共同的事件發(fā)生后同時(shí)開始執(zhí)行。
-
統(tǒng)計(jì)多個(gè)線程的執(zhí)行時(shí)間: 可以用于測(cè)量多個(gè)線程完成任務(wù)所花費(fèi)的總時(shí)間。
下面是一個(gè)簡(jiǎn)單示例,演示了如何使用 CountDownLatch
來(lái)等待多個(gè)線程完成任務(wù):
import java.util.concurrent.CountDownLatch;public class CountDownLatchExample {public static void main(String[] args) throws InterruptedException {int numThreads = 3;CountDownLatch latch = new CountDownLatch(numThreads);for (int i = 0; i < numThreads; i++) {Thread thread = new Thread(() -> {try {// 模擬線程執(zhí)行任務(wù)Thread.sleep(2000);System.out.println(Thread.currentThread().getName() + " has completed.");} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {latch.countDown(); // 任務(wù)執(zhí)行完畢,減少計(jì)數(shù)器}});thread.start();}// 等待所有線程完成latch.await();System.out.println("All threads have completed.");}
}
在上述示例中,我們創(chuàng)建了一個(gè) CountDownLatch
,初始化計(jì)數(shù)器值為 3(表示有三個(gè)線程需要等待)。然后創(chuàng)建了三個(gè)線程,每個(gè)線程執(zhí)行完畢后調(diào)用 countDown()
來(lái)減小計(jì)數(shù)器的值。主線程使用 await()
來(lái)等待計(jì)數(shù)器的值變?yōu)榱?#xff0c;一旦所有線程都執(zhí)行完畢,主線程繼續(xù)執(zhí)行。
CountDownLatch
是一個(gè)常用的同步工具,用于協(xié)調(diào)多個(gè)線程的執(zhí)行,實(shí)現(xiàn)任務(wù)的并發(fā)控制。