Java處理多API請(qǐng)求的方法詳解
Java 中的并發(fā)是指語(yǔ)言并行運(yùn)行多個(gè)線(xiàn)程的能力,允許同時(shí)執(zhí)行多個(gè)任務(wù)。

線(xiàn)程池和Executor框架
一種方法是使用線(xiàn)程池來(lái)管理固定數(shù)量的線(xiàn)程,這些線(xiàn)程可以處理傳入的請(qǐng)求。Java Executor 框架提供了一種方便的方法來(lái)實(shí)現(xiàn)這種方法,換句話(huà)說(shuō),使用線(xiàn)程池和 Executor 框架是在 Java 中實(shí)現(xiàn)并發(fā)和處理多個(gè) API 請(qǐng)求的一種方法。
線(xiàn)程池管理固定數(shù)量的線(xiàn)程,可以有效利用系統(tǒng)資源,防止線(xiàn)程饑餓。
什么是執(zhí)行器框架?

Executor 框架是一個(gè)內(nèi)置的 Java 框架,它提供了一種管理和執(zhí)行線(xiàn)程的方法。它是 java.util.concurrent 包的一部分,在 Java 5 中引入。
Executor 框架在低級(jí) Thread 類(lèi)上提供了更高級(jí)別的抽象,從而更容易并發(fā)執(zhí)行任務(wù),而無(wú)需直接管理線(xiàn)程。它還提供了一種方法來(lái)管理線(xiàn)程池并重用它們來(lái)執(zhí)行多個(gè)任務(wù),從而減少創(chuàng)建和銷(xiāo)毀線(xiàn)程的開(kāi)銷(xiāo)。
Executor框架的核心接口是Executor接口,它定義了一個(gè)單一的方法execute(Runnable)。Executor 接口提供了一種提交 Runnable 任務(wù)以供執(zhí)行的方法。該框架還提供了一些子接口和類(lèi),可以用來(lái)實(shí)現(xiàn)不同類(lèi)型的Executor,例如:
- ExecutorService:一個(gè) Executor,它提供管理終止的方法和可以生成用于跟蹤一個(gè)或多個(gè)異步任務(wù)進(jìn)度的 Future 的方法。
- ScheduledExecutorService:一個(gè) ExecutorService,它可以安排命令在給定延遲后運(yùn)行,或定期執(zhí)行。
- ThreadPoolExecutor:一個(gè) ExecutorService,它使用可能的多個(gè)池線(xiàn)程之一執(zhí)行每個(gè)提交的任務(wù),通常使用 Executors 工廠方法配置。
使用 Executor 框架可以幫助您以高效的方式處理多個(gè) API 請(qǐng)求,方法是管理線(xiàn)程并提供一種將它們重用于多個(gè)任務(wù)的方法,從而減少創(chuàng)建和銷(xiāo)毀線(xiàn)程的開(kāi)銷(xiāo)。
下面是一個(gè)如何使用 Executor 框架高效處理多個(gè) API 請(qǐng)求的示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorExample {
public static void main(String[] args) {
// Create a fixed thread pool with 5 threads
ExecutorService executor = Executors.newFixedThreadPool(5);
// Submit 10 tasks for execution
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(new Runnable() {
@Override
public void run() {
// Perform an API request here
// For example, using the OkHttp library:
// OkHttpClient client = new OkHttpClient();
// Request request = new Request.Builder()
// .url("https://example.com/api/task" + taskId)
// .build();
// Response response = client.newCall(request).execute();
// Do something with the response
System.out.println("Task " + taskId + " completed");
}
});
}
// Shut down the executor
executor.shutdown();
}
}在本例中,我們使用Executors.newFixedThreadPool方法創(chuàng)建一個(gè)具有 5 個(gè)線(xiàn)程的固定線(xiàn)程池。然后,我們使用該executor.submit方法提交 10 個(gè)要執(zhí)行的任務(wù)。每個(gè)任務(wù)代表一個(gè) API 請(qǐng)求,該請(qǐng)求將由線(xiàn)程池中的線(xiàn)程之一執(zhí)行。
提交所有任務(wù)后,shutdown()調(diào)用執(zhí)行器的方法,啟動(dòng)線(xiàn)程池的關(guān)閉。池中的線(xiàn)程將執(zhí)行完提交的任務(wù),然后終止。
請(qǐng)注意,在此示例中,我添加了一個(gè)用于發(fā)出 API 請(qǐng)求的虛擬代碼,它不起作用,您必須使用特定的庫(kù)(如 OkHttp 或 Retrofit)來(lái)進(jìn)行 API 調(diào)用。
您可以在這個(gè)示例中看到,通過(guò)重用固定數(shù)量的線(xiàn)程并通過(guò) Executor 框架管理任務(wù)的執(zhí)行,我們能夠并發(fā)且高效地處理多個(gè) API 請(qǐng)求。
異步 I/O 庫(kù)
在 Java 中實(shí)現(xiàn)并發(fā)的另一種方法是通過(guò)使用異步 I/O (AIO) 庫(kù),它允許非阻塞 I/O 操作,并且可以處理大量并發(fā)連接。
異步 I/O 庫(kù)是一個(gè)允許非阻塞 I/O 操作的庫(kù),這意味著程序可以在等待 I/O 操作完成的同時(shí)繼續(xù)執(zhí)行其他任務(wù)。這在處理大量并發(fā)連接時(shí)很有用,例如在構(gòu)建高性能服務(wù)器時(shí)。
Java 中異步 I/O 庫(kù)的一個(gè)例子是 Java NIO 包,自 Java 1.4 以來(lái)它是標(biāo)準(zhǔn) Java 庫(kù)的一部分。它提供了一組用于執(zhí)行非阻塞 I/O 操作的類(lèi)和接口。
下面是一個(gè)如何使用 Java NIO 包構(gòu)建可以同時(shí)處理多個(gè)客戶(hù)端的簡(jiǎn)單服務(wù)器的示例:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class NioServer {
public static void main(String[] args) throws IOException {
// Open a selector
Selector selector = Selector.open();
// Open a server socket channel
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress(8080));
serverSocket.configureBlocking(false);
// Register the server socket channel with the selector
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// Wait for events
selector.select();
// Iterate over the events
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
// Handle a new connection
if (key.isAcceptable()) {
ServerSocketChannel channel = (ServerSocketChannel) key.channel();
SocketChannel client = channel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
}
// Handle a read event
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = client.read(buffer);
if (read > 0) {
buffer.flip();
String message = new String(buffer.array(), 0, read);
System.out.println("Received: " + message);
}
}
iterator.remove();
}
}
}
}在這個(gè)例子中,我們首先打開(kāi)一個(gè)Selector對(duì)象和一個(gè)ServerSocketChannel. 被ServerSocketChannel配置為非阻塞的并注冊(cè)到Selector. 然后我們進(jìn)入一個(gè)無(wú)限循環(huán),等待已注冊(cè)頻道上的事件。
當(dāng)接受新連接時(shí),我們SocketChannel為客戶(hù)端創(chuàng)建一個(gè)新連接并將其注冊(cè)到Selectorfor read 事件。當(dāng)檢測(cè)到讀取事件時(shí),我們將數(shù)據(jù)從客戶(hù)端讀取到緩沖區(qū)中并將其打印到控制臺(tái)。
可以看到,通過(guò)使用 Java NIO 包,我們可以同時(shí)處理多個(gè)客戶(hù)端,而不會(huì)阻塞程序的執(zhí)行。Selector以及ServerSocketChannel。
OkHttp 和 Retrofit
使用像 OkHttp 或 Retrofit 這樣的庫(kù)的概念也與并發(fā)密切相關(guān),因?yàn)樗橄罅说讓泳W(wǎng)絡(luò)和線(xiàn)程實(shí)現(xiàn),使開(kāi)發(fā)人員可以輕松高效地處理多個(gè)請(qǐng)求。
OkHttp
OkHttp 是一個(gè)流行的 Java 庫(kù),用于發(fā)出 HTTP 請(qǐng)求。它為執(zhí)行同步和異步請(qǐng)求提供了一個(gè)簡(jiǎn)單高效的 API。它還包括連接池、透明 GZIP 壓縮和響應(yīng)緩存等功能。
下面是如何使用 OkHttp 在多線(xiàn)程環(huán)境中發(fā)出異步 GET 請(qǐng)求的示例。
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class OkHttpAsyncExample {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://jsonplaceholder.typicode.com/todos/1")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
String responseBody = response.body().string();
System.out.println(responseBody);
}
});
}
}在這個(gè)例子中,我們首先創(chuàng)建一個(gè)實(shí)例,OkHttpClient它是線(xiàn)程安全的,可以被多個(gè)請(qǐng)求共享。然后我們創(chuàng)建一個(gè)新Request對(duì)象,指定我們要調(diào)用的 URL。
然后我們使用該enqueue方法異步執(zhí)行請(qǐng)求。該enqueue方法采用一個(gè)Callback對(duì)象,在請(qǐng)求完成或失敗時(shí)調(diào)用該對(duì)象。在此示例中,我們?cè)诔晒r(shí)打印響應(yīng)主體,在失敗時(shí)打印異常堆棧跟蹤。
當(dāng)你有多個(gè)傳入的 API 請(qǐng)求時(shí),你可以對(duì)所有請(qǐng)求使用同一個(gè) OkHttpClient 實(shí)例,所有請(qǐng)求都將由 OkHttp 異步處理。該enqueue方法立即返回,允許您的應(yīng)用程序在后臺(tái)獲取響應(yīng)的同時(shí)繼續(xù)處理其他請(qǐng)求或任務(wù)。這有助于防止阻塞程序的執(zhí)行并確保在處理大量并發(fā)連接時(shí)具有良好的性能。
改裝
下面是如何使用 Retrofit 在多線(xiàn)程環(huán)境中發(fā)出異步 GET 請(qǐng)求的示例。
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitAsyncExample {
public static void main(String[] args) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
JsonPlaceholderApi jsonPlaceholderApi = retrofit.create(JsonPlaceholderApi.class);
Call<Todo> call = jsonPlaceholderApi.getTodo(1);
call.enqueue(new Callback<Todo>() {
@Override
public void onResponse(Call<Todo> call, Response<Todo> response) {
if (!response.isSuccessful()) {
System.out.println("Unexpected code " + response);
return;
}
Todo todo = response.body();
System.out.println(todo);
}
@Override
public void onFailure(Call<Todo> call, Throwable t) {
t.printStackTrace();
}
});
}
}
interface JsonPlaceholderApi {
@GET("todos/{id}")
Call<Todo> getTodo(@Path("id") int id);
}
class Todo {
int userId;
int id;
String title;
boolean completed;
// getters and setters
}在此示例中,我們首先Retrofit通過(guò)指定我們要調(diào)用的 API 的基本 URL 并添加一個(gè) GSON 轉(zhuǎn)換器工廠來(lái)創(chuàng)建一個(gè)實(shí)例。JsonPlaceholderApi然后我們使用 Retrofit 的方法創(chuàng)建一個(gè)接口create的實(shí)現(xiàn)來(lái)獲取服務(wù)的實(shí)現(xiàn)。
然后我們調(diào)用getTodo接口的方法,傳遞我們要檢索的待辦事項(xiàng)的 ID。這將返回一個(gè)Call對(duì)象,我們可以使用該對(duì)象通過(guò)調(diào)用異步執(zhí)行請(qǐng)求enqueue。
該enqueue方法采用一個(gè)Callback對(duì)象,在請(qǐng)求完成或失敗時(shí)調(diào)用該對(duì)象。在此示例中,我們?cè)诔晒r(shí)打印響應(yīng)主體,在失敗時(shí)打印異常堆棧跟蹤。
當(dāng)你有多個(gè)傳入的 API 請(qǐng)求時(shí),你可以對(duì)所有請(qǐng)求使用相同的 Retrofit 實(shí)例,所有請(qǐng)求將由 Retrofit 異步處理。該enqueue方法立即返回,允許您的應(yīng)用程序在后臺(tái)獲取響應(yīng)的同時(shí)繼續(xù)處理其他請(qǐng)求或任務(wù)。這有助于防止阻塞程序的執(zhí)行并確保在處理大量并發(fā)連接時(shí)具有良好的性能。
總之,以高效方式處理多個(gè) API 請(qǐng)求的概念與 Java 中的并發(fā)性密切相關(guān),可以通過(guò)使用線(xiàn)程池、異步 I/O (AIO) 庫(kù)以及 OkHttp 或 Retrofit 等庫(kù)來(lái)實(shí)現(xiàn)。
以上就是Java處理多API請(qǐng)求的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Java處理多API請(qǐng)求的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot接收json數(shù)據(jù)時(shí),接收到空值問(wèn)題
這篇文章主要介紹了springboot接收json數(shù)據(jù)時(shí),接收到空值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
Springboot+SpringSecurity實(shí)現(xiàn)圖片驗(yàn)證碼登錄的示例
本文主要介紹了Springboot+SpringSecurity實(shí)現(xiàn)圖片驗(yàn)證碼登錄的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
PowerJob分布式任務(wù)調(diào)度源碼流程解讀
這篇文章主要為大家介紹了PowerJob分布式任務(wù)調(diào)度源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-02-02
struts2實(shí)現(xiàn)多文件上傳的示例代碼
本篇文章主要介紹了struts2實(shí)現(xiàn)多文件上傳的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
springboot2.0使用Hikari連接池的方法(替換druid)
這篇文章主要介紹了springboot 2.0使用Hikari連接池的方法(替換druid),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
解析spring-boot-starter-parent簡(jiǎn)介
本文通過(guò)代碼的形式給大家介紹了spring-boot-starter-parent的基礎(chǔ)知識(shí),需要的朋友可以參考下2018-09-09

