金秋十月桂花香,舉國(guó)歡騰迎國(guó)慶。 紅旗飄飄映日紅,歌聲嘹亮震云霄。
江山如此多嬌,引無數(shù)英雄競(jìng)折腰。 今朝有酒今朝醉,明日朝陽(yáng)更輝煌。
國(guó)泰民安歌盛世,家和萬事興四方。 愿君國(guó)慶好心情,快樂幸福伴你行。
歲月如歌樂未央,國(guó)慶佳節(jié)喜洋洋。 祝福祖國(guó)更昌盛,人民幸福樂無疆。
希望這段詩(shī)詞能為你的國(guó)慶增添一份古典韻味和美好祝愿!
大家好,我是 V 哥,今天要給大家分享的是無界隊(duì)列(Unbounded Queue)和有界隊(duì)列(Bounded Queue)是兩種常見的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)和管理數(shù)據(jù)項(xiàng)。在計(jì)算機(jī)科學(xué)和并發(fā)編程中,它們有不同的特性和應(yīng)用場(chǎng)景。下面詳細(xì)解釋這兩者的概念、特點(diǎn)和適用場(chǎng)景。
點(diǎn)贊收藏加關(guān)注,高效學(xué)習(xí)不迷路
。
無界隊(duì)列是指在邏輯上沒有限制隊(duì)列中可以容納的元素?cái)?shù)量的隊(duì)列。也就是說,無論向隊(duì)列中添加多少元素,隊(duì)列都能夠處理,而不會(huì)因?yàn)槌瞿硞€(gè)限制而拋出異常或阻塞操作。
下面是一個(gè)使用Java實(shí)現(xiàn)異步任務(wù)調(diào)度的示例,使用無界隊(duì)列(BlockingQueue
)來存放任務(wù),消費(fèi)者可以隨時(shí)從隊(duì)列中取出任務(wù)進(jìn)行處理。
在異步任務(wù)調(diào)度中,生產(chǎn)者不斷生成任務(wù)并將其放入隊(duì)列,而消費(fèi)者則從隊(duì)列中取出任務(wù)并處理。無界隊(duì)列允許生產(chǎn)者在任何時(shí)候放入任務(wù),而不會(huì)因?yàn)殛?duì)列已滿而阻塞,適合于處理流量波動(dòng)的場(chǎng)景。
我們使用LinkedBlockingQueue
來實(shí)現(xiàn)無界隊(duì)列,并創(chuàng)建生產(chǎn)者和消費(fèi)者線程。
我們使用Maven構(gòu)建項(xiàng)目,在pom.xml
中添加以下依賴:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
</dependencies>
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
class Task {
private final String name;
public Task(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Task{" + "name='" + name + '\'' + '}';
}
}
// 生產(chǎn)者類
class TaskProducer implements Runnable {
private final BlockingQueue<Task> taskQueue;
public TaskProducer(BlockingQueue<Task> taskQueue) {
this.taskQueue = taskQueue;
}
@Override
public void run() {
int taskCount = 0;
while (true) {
try {
// 模擬任務(wù)生成
Task task = new Task("Task-" + taskCount++);
System.out.println("Producing " + task);
taskQueue.put(task); // 將任務(wù)放入隊(duì)列
Thread.sleep(100); // 模擬生產(chǎn)間隔
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
// 消費(fèi)者類
class TaskConsumer implements Runnable {
private final BlockingQueue<Task> taskQueue;
public TaskConsumer(BlockingQueue<Task> taskQueue) {
this.taskQueue = taskQueue;
}
@Override
public void run() {
while (true) {
try {
Task task = taskQueue.take(); // 從隊(duì)列中取出任務(wù)
System.out.println("Consuming " + task);
Thread.sleep(200); // 模擬處理時(shí)間
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
public class AsyncTaskScheduler {
public static void main(String[] args) {
BlockingQueue<Task> taskQueue = new LinkedBlockingQueue<>(); // 創(chuàng)建無界隊(duì)列
// 啟動(dòng)生產(chǎn)者線程
Thread producerThread = new Thread(new TaskProducer(taskQueue));
producerThread.start();
// 啟動(dòng)消費(fèi)者線程
Thread consumerThread = new Thread(new TaskConsumer(taskQueue));
consumerThread.start();
// 讓線程運(yùn)行一段時(shí)間后停止
try {
Thread.sleep(5000); // 運(yùn)行5秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
producerThread.interrupt(); // 中斷生產(chǎn)者線程
consumerThread.interrupt(); // 中斷消費(fèi)者線程
}
}
}
Runnable
接口,負(fù)責(zé)生成任務(wù)并將其放入隊(duì)列。BlockingQueue
來存放任務(wù),通過taskQueue.put(task)
將任務(wù)放入隊(duì)列。Thread.sleep(100)
模擬任務(wù)生成的時(shí)間間隔。Runnable
接口,負(fù)責(zé)從隊(duì)列中取出任務(wù)并處理。taskQueue.take()
從隊(duì)列中取出任務(wù),如果隊(duì)列為空,它將阻塞直到有任務(wù)可用。Thread.sleep(200)
模擬處理任務(wù)的時(shí)間。LinkedBlockingQueue
實(shí)例作為無界隊(duì)列。運(yùn)行這個(gè)程序時(shí),控制臺(tái)會(huì)顯示生產(chǎn)者生成的任務(wù)和消費(fèi)者處理的任務(wù)。由于使用的是無界隊(duì)列,生產(chǎn)者可以不斷生成任務(wù)而不會(huì)被阻塞,消費(fèi)者則可以從隊(duì)列中取出任務(wù)并處理。
在事件驅(qū)動(dòng)的系統(tǒng)中,無界隊(duì)列可以用來接收和處理大量的事件。這種設(shè)計(jì)使得事件的生產(chǎn)者可以快速將事件放入隊(duì)列,而消費(fèi)者則可以異步地處理這些事件。以下是一個(gè)使用Java實(shí)現(xiàn)此應(yīng)用場(chǎng)景的示例。
在事件驅(qū)動(dòng)的系統(tǒng)中,事件生產(chǎn)者會(huì)不斷產(chǎn)生事件(如用戶操作、系統(tǒng)通知等),并將其放入無界隊(duì)列中。事件消費(fèi)者則從隊(duì)列中異步讀取這些事件并進(jìn)行處理,例如發(fā)送通知、更新數(shù)據(jù)庫(kù)或觸發(fā)其他操作。無界隊(duì)列確保生產(chǎn)者不會(huì)因?yàn)槭录幚硭俣嚷蛔枞?/p>
我們使用BlockingQueue
來實(shí)現(xiàn)無界隊(duì)列,并創(chuàng)建生產(chǎn)者和消費(fèi)者線程來處理事件。
用Maven構(gòu)建項(xiàng)目,添加slf4j依賴:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
</dependencies>
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
// 事件類
class Event {
private final String message;
public Event(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return "Event{" + "message='" + message + '\'' + '}';
}
}
// 事件生產(chǎn)者類
class EventProducer implements Runnable {
private final BlockingQueue<Event> eventQueue;
public EventProducer(BlockingQueue<Event> eventQueue) {
this.eventQueue = eventQueue;
}
@Override
public void run() {
int eventCount = 0;
while (true) {
try {
// 模擬事件生成
Event event = new Event("Event-" + eventCount++);
System.out.println("Producing " + event);
eventQueue.put(event); // 將事件放入隊(duì)列
Thread.sleep(50); // 模擬生產(chǎn)間隔
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
// 事件消費(fèi)者類
class EventConsumer implements Runnable {
private final BlockingQueue<Event> eventQueue;
public EventConsumer(BlockingQueue<Event> eventQueue) {
this.eventQueue = eventQueue;
}
@Override
public void run() {
while (true) {
try {
Event event = eventQueue.take(); // 從隊(duì)列中取出事件
System.out.println("Consuming " + event);
Thread.sleep(100); // 模擬處理時(shí)間
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
public class EventDrivenSystem {
public static void main(String[] args) {
BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<>(); // 創(chuàng)建無界隊(duì)列
// 啟動(dòng)事件生產(chǎn)者線程
Thread producerThread = new Thread(new EventProducer(eventQueue));
producerThread.start();
// 啟動(dòng)事件消費(fèi)者線程
Thread consumerThread = new Thread(new EventConsumer(eventQueue));
consumerThread.start();
// 讓線程運(yùn)行一段時(shí)間后停止
try {
Thread.sleep(5000); // 運(yùn)行5秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
producerThread.interrupt(); // 中斷生產(chǎn)者線程
consumerThread.interrupt(); // 中斷消費(fèi)者線程
}
}
}
Runnable
接口,負(fù)責(zé)生成事件并將其放入事件隊(duì)列。BlockingQueue<Event>
來存放事件,通過eventQueue.put(event)
將事件放入隊(duì)列。Thread.sleep(50)
模擬事件生成的時(shí)間間隔。Runnable
接口,負(fù)責(zé)從隊(duì)列中取出事件并進(jìn)行處理。eventQueue.take()
從隊(duì)列中取出事件,如果隊(duì)列為空,則阻塞等待事件。Thread.sleep(100)
模擬處理事件的時(shí)間。LinkedBlockingQueue
實(shí)例作為無界隊(duì)列。運(yùn)行此程序時(shí),控制臺(tái)會(huì)顯示生產(chǎn)者生成的事件和消費(fèi)者處理的事件。由于使用的是無界隊(duì)列,生產(chǎn)者可以快速生成事件而不會(huì)被阻塞,而消費(fèi)者則會(huì)異步地從隊(duì)列中取出事件進(jìn)行處理。
通過這個(gè)示例,咱們可以看到如何在Java中使用無界隊(duì)列實(shí)現(xiàn)事件驅(qū)動(dòng)系統(tǒng)。生產(chǎn)者不斷生成事件并放入隊(duì)列,消費(fèi)者則異步處理這些事件,提升了系統(tǒng)的響應(yīng)速度和處理能力。這種設(shè)計(jì)模式適用于高并發(fā)、高流量的系統(tǒng),能夠有效管理資源并提升系統(tǒng)的整體性能。
有界隊(duì)列是指在邏輯上限制了隊(duì)列中可以容納的元素?cái)?shù)量的隊(duì)列。隊(duì)列在初始化時(shí)設(shè)置一個(gè)最大容量,當(dāng)達(dá)到該容量時(shí),再嘗試添加新元素將會(huì)失敗或阻塞。
在生產(chǎn)者-消費(fèi)者問題中,有界隊(duì)列用于限制生產(chǎn)者可以生成的任務(wù)數(shù)量,從而避免內(nèi)存耗盡的情況。在這種模式中,生產(chǎn)者線程負(fù)責(zé)生成任務(wù)并將其放入隊(duì)列,而消費(fèi)者線程則從隊(duì)列中取出任務(wù)進(jìn)行處理。有界隊(duì)列通過設(shè)置一個(gè)最大容量來限制隊(duì)列中的任務(wù)數(shù)量。當(dāng)隊(duì)列已滿時(shí),生產(chǎn)者會(huì)被阻塞,直到消費(fèi)者取走一些任務(wù),從而釋放出空間。
以下是一個(gè)使用Java實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者問題的示例,使用有界隊(duì)列(ArrayBlockingQueue
)來限制隊(duì)列的容量。
在這個(gè)應(yīng)用場(chǎng)景中,生產(chǎn)者線程生成任務(wù)并放入有界隊(duì)列,而消費(fèi)者線程從隊(duì)列中取出任務(wù)并處理。通過這種方式,可以有效管理內(nèi)存,防止生產(chǎn)者生成過多任務(wù)而導(dǎo)致系統(tǒng)資源耗盡。
我們使用ArrayBlockingQueue
來實(shí)現(xiàn)有界隊(duì)列,并創(chuàng)建生產(chǎn)者和消費(fèi)者線程。
用Maven構(gòu)建項(xiàng)目,在pom.xml
中添加以下依賴:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
</dependencies>
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
// 任務(wù)類
class Task {
private final String name;
public Task(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Task{" + "name='" + name + '\'' + '}';
}
}
// 生產(chǎn)者類
class TaskProducer implements Runnable {
private final BlockingQueue<Task> taskQueue;
public TaskProducer(BlockingQueue<Task> taskQueue) {
this.taskQueue = taskQueue;
}
@Override
public void run() {
int taskCount = 0;
while (true) {
try {
// 模擬任務(wù)生成
Task task = new Task("Task-" + taskCount++);
System.out.println("Producing " + task);
taskQueue.put(task); // 將任務(wù)放入隊(duì)列
Thread.sleep(100); // 模擬生產(chǎn)間隔
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
// 消費(fèi)者類
class TaskConsumer implements Runnable {
private final BlockingQueue<Task> taskQueue;
public TaskConsumer(BlockingQueue<Task> taskQueue) {
this.taskQueue = taskQueue;
}
@Override
public void run() {
while (true) {
try {
Task task = taskQueue.take(); // 從隊(duì)列中取出任務(wù)
System.out.println("Consuming " + task);
Thread.sleep(200); // 模擬處理時(shí)間
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
public class ProducerConsumerProblem {
public static void main(String[] args) {
BlockingQueue<Task> taskQueue = new ArrayBlockingQueue<>(5); // 創(chuàng)建有界隊(duì)列,最大容量為5
// 啟動(dòng)生產(chǎn)者線程
Thread producerThread = new Thread(new TaskProducer(taskQueue));
producerThread.start();
// 啟動(dòng)消費(fèi)者線程
Thread consumerThread = new Thread(new TaskConsumer(taskQueue));
consumerThread.start();
// 讓線程運(yùn)行一段時(shí)間后停止
try {
Thread.sleep(10000); // 運(yùn)行10秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
producerThread.interrupt(); // 中斷生產(chǎn)者線程
consumerThread.interrupt(); // 中斷消費(fèi)者線程
}
}
}
Runnable
接口,負(fù)責(zé)生成任務(wù)并將其放入任務(wù)隊(duì)列。BlockingQueue<Task>
來存放任務(wù),通過taskQueue.put(task)
將任務(wù)放入隊(duì)列。如果隊(duì)列已滿,生產(chǎn)者會(huì)被阻塞,直到有空間可用。Thread.sleep(100)
模擬任務(wù)生成的時(shí)間間隔。Runnable
接口,負(fù)責(zé)從隊(duì)列中取出任務(wù)并進(jìn)行處理。taskQueue.take()
從隊(duì)列中取出任務(wù),如果隊(duì)列為空,消費(fèi)者會(huì)被阻塞,直到有任務(wù)可用。Thread.sleep(200)
模擬處理任務(wù)的時(shí)間。ArrayBlockingQueue
實(shí)例作為有界隊(duì)列,最大容量為5。運(yùn)行這個(gè)程序時(shí),控制臺(tái)會(huì)顯示生產(chǎn)者生成的任務(wù)和消費(fèi)者處理的任務(wù)。由于使用的是有界隊(duì)列,當(dāng)隊(duì)列達(dá)到最大容量時(shí),生產(chǎn)者會(huì)被阻塞,直到消費(fèi)者取走任務(wù),釋放出空間。這種機(jī)制有效地防止了生產(chǎn)者過量生產(chǎn)任務(wù)導(dǎo)致內(nèi)存耗盡的情況。
通過這個(gè)示例,咱們可以看到如何在Java中使用有界隊(duì)列實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者問題。生產(chǎn)者在隊(duì)列達(dá)到最大容量時(shí)被阻塞,確保了不會(huì)因?yàn)樯蛇^多任務(wù)而導(dǎo)致內(nèi)存耗盡。這種設(shè)計(jì)模式有效地管理了資源,提高了系統(tǒng)的穩(wěn)定性和可預(yù)測(cè)性。
在高流量的API中,使用有界隊(duì)列可以有效地控制請(qǐng)求的處理速度,從而防止系統(tǒng)過載。通過限制請(qǐng)求的數(shù)量,有界隊(duì)列能夠保證系統(tǒng)在高并發(fā)情況下仍然能夠穩(wěn)定運(yùn)行。以下是一個(gè)使用Java實(shí)現(xiàn)限流控制的示例,使用有界隊(duì)列(ArrayBlockingQueue
)來處理請(qǐng)求。
在這個(gè)應(yīng)用場(chǎng)景中,API接收客戶端的請(qǐng)求,將請(qǐng)求放入有界隊(duì)列中,消費(fèi)者線程從隊(duì)列中取出請(qǐng)求進(jìn)行處理。通過設(shè)定隊(duì)列的容量,可以有效控制請(qǐng)求的處理速度,確保系統(tǒng)不會(huì)因?yàn)檎?qǐng)求過多而崩潰。
我們使用ArrayBlockingQueue
來實(shí)現(xiàn)有界隊(duì)列,并創(chuàng)建請(qǐng)求生產(chǎn)者和消費(fèi)者線程。
使用Maven構(gòu)建項(xiàng)目,在pom.xml
中添加以下依賴:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
</dependencies>
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
// 請(qǐng)求類
class Request {
private final String clientId;
public Request(String clientId) {
this.clientId = clientId;
}
public String getClientId() {
return clientId;
}
@Override
public String toString() {
return "Request{" + "clientId='" + clientId + '\'' + '}';
}
}
// 請(qǐng)求生產(chǎn)者類
class RequestProducer implements Runnable {
private final BlockingQueue<Request> requestQueue;
public RequestProducer(BlockingQueue<Request> requestQueue) {
this.requestQueue = requestQueue;
}
@Override
public void run() {
int requestCount = 0;
while (true) {
try {
// 模擬請(qǐng)求生成
Request request = new Request("Client-" + requestCount++);
System.out.println("Producing " + request);
requestQueue.put(request); // 將請(qǐng)求放入隊(duì)列
Thread.sleep(50); // 模擬生產(chǎn)請(qǐng)求的間隔
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
// 請(qǐng)求消費(fèi)者類
class RequestConsumer implements Runnable {
private final BlockingQueue<Request> requestQueue;
public RequestConsumer(BlockingQueue<Request> requestQueue) {
this.requestQueue = requestQueue;
}
@Override
public void run() {
while (true) {
try {
Request request = requestQueue.take(); // 從隊(duì)列中取出請(qǐng)求
System.out.println("Consuming " + request);
Thread.sleep(100); // 模擬處理請(qǐng)求的時(shí)間
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
break;
}
}
}
}
public class RateLimitingControl {
public static void main(String[] args) {
BlockingQueue<Request> requestQueue = new ArrayBlockingQueue<>(5); // 創(chuàng)建有界隊(duì)列,最大容量為5
// 啟動(dòng)請(qǐng)求生產(chǎn)者線程
Thread producerThread = new Thread(new RequestProducer(requestQueue));
producerThread.start();
// 啟動(dòng)請(qǐng)求消費(fèi)者線程
Thread consumerThread = new Thread(new RequestConsumer(requestQueue));
consumerThread.start();
// 讓線程運(yùn)行一段時(shí)間后停止
try {
Thread.sleep(10000); // 運(yùn)行10秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
producerThread.interrupt(); // 中斷生產(chǎn)者線程
consumerThread.interrupt(); // 中斷消費(fèi)者線程
}
}
}
Runnable
接口,負(fù)責(zé)生成請(qǐng)求并將其放入請(qǐng)求隊(duì)列。BlockingQueue<Request>
來存放請(qǐng)求,通過requestQueue.put(request)
將請(qǐng)求放入隊(duì)列。如果隊(duì)列已滿,生產(chǎn)者會(huì)被阻塞,直到有空間可用。Thread.sleep(50)
模擬請(qǐng)求生成的時(shí)間間隔。Runnable
接口,負(fù)責(zé)從隊(duì)列中取出請(qǐng)求并進(jìn)行處理。requestQueue.take()
從隊(duì)列中取出請(qǐng)求,如果隊(duì)列為空,消費(fèi)者會(huì)被阻塞,直到有請(qǐng)求可用。Thread.sleep(100)
模擬處理請(qǐng)求的時(shí)間。ArrayBlockingQueue
實(shí)例作為有界隊(duì)列,最大容量為5。運(yùn)行這個(gè)程序時(shí),控制臺(tái)會(huì)顯示生產(chǎn)者生成的請(qǐng)求和消費(fèi)者處理的請(qǐng)求。由于使用的是有界隊(duì)列,當(dāng)隊(duì)列達(dá)到最大容量時(shí),生產(chǎn)者會(huì)被阻塞,直到消費(fèi)者取走請(qǐng)求,釋放出空間。這種機(jī)制有效地控制了請(qǐng)求的處理速度,確保了系統(tǒng)不會(huì)因?yàn)檎?qǐng)求過多而過載。
通過這個(gè)示例,咱們可以看到如何在Java中使用有界隊(duì)列實(shí)現(xiàn)API的限流控制。生產(chǎn)者在隊(duì)列達(dá)到最大容量時(shí)被阻塞,確保了不會(huì)因?yàn)樯蛇^多請(qǐng)求而導(dǎo)致系統(tǒng)過載。這種設(shè)計(jì)模式有效地管理了資源,提高了系統(tǒng)的穩(wěn)定性和可預(yù)測(cè)性。在高流量的API場(chǎng)景中,限流控制是確保服務(wù)質(zhì)量的重要手段。
理解這兩種隊(duì)列的特性和應(yīng)用場(chǎng)景,能夠幫助我們?cè)诓煌臉I(yè)務(wù)需求中選擇合適的數(shù)據(jù)結(jié)構(gòu),以提高系統(tǒng)的性能和穩(wěn)定性。原創(chuàng)不易,關(guān)注威哥愛編程,一起學(xué)習(xí) Java 的點(diǎn)點(diǎn)滴滴。
更多建議: