轉載請以鏈接形式標明出處:
本文出自:103style的博客
base on 3.12.0
目錄
- 簡介
Dispatcher
成員變量介紹Dispatcher
構造方法介紹Dispatcher
主要方法介紹- 小結
簡介
首先我們來介紹下 Dispatcher
,官方描述是這樣的:
Policy on when async requests are executed.
執行異步請求時的策略
所以Dispatcher
是我們進行異步請求是 okhttp
給我們提供的 執行異步請求時的策略.
public final class Dispatcher {...}
我們可以看到 Dispatcher
類是由 final
修飾的,代表它不能被繼承。
我們先來看下 Dispatcher
是什麼時候設置的。
通過查看下面 OkHttpClient
的代碼,我們知道在我們創建 OkHttpClient
的時候,如果我們沒有通過 builder.dispatcher(Dispatcher dispatcher)
修改 Dispatcher
的配置的話,默認的 dispatcher
就是 默認配置的 Dispatcher
類。
public class OkHttpClient implements ... {
...
public Builder newBuilder() {
return new Builder(this);
}
public static final class Builder {
Dispatcher dispatcher;
...
public Builder() {
dispatcher = new Dispatcher();
...
}
public Builder dispatcher(Dispatcher dispatcher) {
if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null");
this.dispatcher = dispatcher;
return this;
}
}
}
Dispatcher成員變量介紹
-
int maxRequests = 64;
默認同時執行的最大請求數, 可以通過setMaxRequests(int)
修改. -
int maxRequestsPerHost = 5;
每個主機默認請求的最大數目, 可以通過setMaxRequestsPerHost(int)
修改. -
private @Nullable Runnable idleCallback;
調度沒有請求任務時的回調. -
ExecutorService executorService;
執行異步請求的線程池,默認是 核心線程爲0,最大線程數爲Integer.MAX_VALUE
,空閒等待爲60s. -
Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
異步請求的執行順序的隊列. -
Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
運行中的異步請求隊列. -
Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
運行中的同步請求隊列.
Dispatcher構造函數
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {}
可以自己設置執行任務的線程池。
Dispatcher主要方法介紹
- 配置和獲取 同時執行請求的最大任務數、同主機允許同時執行的最大任務數
public void setMaxRequests(int maxRequests) {...} public synchronized int getMaxRequests() {...} public void setMaxRequestsPerHost(int maxRequestsPerHost) {...} public synchronized int getMaxRequestsPerHost() {...}
- 設置沒有請求任務時的回調
public synchronized void setIdleCallback(@Nullable Runnable idleCallback) { this.idleCallback = idleCallback; }
- 添加到請求隊列
void enqueue(AsyncCall call) { synchronized (this) { readyAsyncCalls.add(call); } promoteAndExecute(); } synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
- 執行等待隊列中的請求任務
private boolean promoteAndExecute() { assert (!Thread.holdsLock(this)); List<AsyncCall> executableCalls = new ArrayList<>(); boolean isRunning; synchronized (this) { //獲取等待中的任務隊列 for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { AsyncCall asyncCall = i.next(); // 超過可以同時運行的最大請求任務數 if (runningAsyncCalls.size() >= maxRequests) break; // 超過同一主機同時運行的最大請求任務數 if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; i.remove(); executableCalls.add(asyncCall); runningAsyncCalls.add(asyncCall); } isRunning = runningCallsCount() > 0; } for (int i = 0, size = executableCalls.size(); i < size; i++) { AsyncCall asyncCall = executableCalls.get(i); asyncCall.executeOn(executorService()); } return isRunning; }
- 獲取執行任務的線程池.
如果沒有通過構造方法Dispatcher(ExecutorService executorService)
設置線程池的話,默認就是 核心線程爲0,最大線程數爲Integer.MAX_VALUE
,空閒等待爲60s,用SynchronousQueue
保存等待任務 的線程池。public synchronized ExecutorService executorService() { if (executorService == null) { executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false)); } return executorService; }
- 獲取和當前請求的host一樣的運行中的請求個數.
private int runningCallsForHost(AsyncCall call) { int result = 0; for (AsyncCall c : runningAsyncCalls) { if (c.get().forWebSocket) continue; if (c.host().equals(call.host())) result++; } return result; }
- 取消所有請求任務
public synchronized void cancelAll() { for (AsyncCall call : readyAsyncCalls) { call.get().cancel(); } for (AsyncCall call : runningAsyncCalls) { call.get().cancel(); } for (RealCall call : runningSyncCalls) { call.cancel(); } }
- 結束請求任務
void finished(AsyncCall call) {} void finished(RealCall call) {} private <T> void finished(Deque<T> calls, T call) { Runnable idleCallback; synchronized (this) { if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); idleCallback = this.idleCallback; } boolean isRunning = promoteAndExecute(); if (!isRunning && idleCallback != null) { idleCallback.run(); } }
- 獲取等待中、執行中的請求任務
public synchronized List<Call> queuedCalls() { List<Call> result = new ArrayList<>(); for (AsyncCall asyncCall : readyAsyncCalls) { result.add(asyncCall.get()); } return Collections.unmodifiableList(result); } public synchronized List<Call> runningCalls() { List<Call> result = new ArrayList<>(); result.addAll(runningSyncCalls); for (AsyncCall asyncCall : runningAsyncCalls) { result.add(asyncCall.get()); } return Collections.unmodifiableList(result); } public synchronized int queuedCallsCount() { return readyAsyncCalls.size(); } public synchronized int runningCallsCount() { return runningAsyncCalls.size() + runningSyncCalls.size(); }
小結
Dispatcher
是我們進行異步請求是 okhttp
給我們提供的 執行異步請求時的策略。
Dispatcher
因爲是final
修飾的類,所以我們我能繼承它,但是我們可以通過創建一個Dispatcher
對象,然後修改 執行任務的線程池、 最大併發數、 同主機最大併發數 等。
執行任務的方法是promoteAndExecute()
.
以上