Android小知識-剖析OkHttp中的任務排程器Dispatcher
本平臺的文章更新會有延遲,大家可以關注微信公眾號-顧林海,包括年底前會更新kotlin由淺入深系列教程,目前計劃在微信公眾號進行首發,如果大家想獲取最新教程,請關注微信公眾號,謝謝
OkHttp傳送的同步或非同步請求佇列的狀態會在dispatcher中進行管理,dispatcher的作用就是用於維護同步和非同步請求的狀態,內部維護一個執行緒池,用於執行相應的請求。
在dispatcher內部維護著三個佇列,這三個佇列如下:
private final Deque<RealCall.AsyncCall> readyAsyncCalls = new ArrayDeque<>(); private final Deque<RealCall.AsyncCall> runningAsyncCalls = new ArrayDeque<>(); private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
runningAsyncCalls表示的是正在執行的非同步請求佇列。
readyAsyncCalls表示就緒狀態的非同步請求佇列,如果當前的請求不滿足某種條件時,當前的非同步請求會進入就緒等待的非同步請求佇列中,當滿足某種條件時,會從就緒等待的非同步請求佇列中取出非同步請求,放入正在執行的非同步請求佇列中。
runningSyncCalls表示的正在執行的同步請求佇列。
除了上面的三個佇列,還有一個引數也是非常重要的,如下:
private @Nullable ExecutorService executorService;
executorService就是一個執行緒池物件,OkHttp的非同步請求操作會放入這個執行緒池中。
OkHttp的非同步請求在dispatcher中的一系列操作可以理解為生產者消費者模式,其中Dispatcher是生產者,它是執行在主執行緒中的,ExecutorService代表消費者池。
當同步和非同步請求結束後,會呼叫dispatcher的finished方法,將當前的請求從佇列中移除。
client.dispatcher().finished(this);
這段程式碼是在finally塊中,也就是說,無論請求成不成功,還是出現異常,這段程式碼都會執行,保證了請求的整個生命週期從開始到銷燬。
接下來,我們重新看看同步請求和非同步請求在dispatcher中的操作。
1、同步請求會執行dispatcher的executed方法:
synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
在executed方法中,只是將當前請求RealCall存入正在執行的同步請求佇列中。
2、非同步請求會執行dispatcher的enqueue方法;
private int maxRequests = 64; private int maxRequestsPerHost = 5; synchronized void enqueue(RealCall.AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { //第一步 runningAsyncCalls.add(call); executorService().execute(call); } else { //第二步 readyAsyncCalls.add(call); } }
上一節在講解非同步請求時已經解釋過了,這裡直接複製過來:在enqueue方法前使用了synchronized關鍵字進行修飾,也就是為這個方法加了個同步鎖,繼續往下看第一步,先是判斷當前非同步請求總數是否小於設定的最大請求數(預設是64),以及正在執行的每個主機請求數是否小於設定的主機最大請求數(預設是5),如果滿足這兩個條件,就會把傳遞進來的AsyncCall物件新增到正在執行的非同步請求佇列中,然後通過執行緒池執行這個請求。如果滿足不了上面的兩個條件就會走第二步,將AsyncCall物件存入readyAsyncCalls佇列中,這個readyAsyncCalls就是用來存放等待請求的一個非同步佇列。
其中執行緒池的建立和獲取程式碼如下:
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; }
建立執行緒池時,第一個引數表示核心執行緒數,設定為0,當執行緒池空閒一段時間後,就會將執行緒池中的所有執行緒進行銷燬;第二個引數表示最大執行緒數,設定為整型的最大值,具體多少執行緒數還是受限OkHttp中的maxRequests這個引數;第三個引數表示當我們的執行緒數大於核心執行緒數的時候,多餘的空閒執行緒存活的最大時間為60秒,結合第一個核心執行緒數為0,也就是說OkHttp中的執行緒在工作完畢後,會在60秒後進行關閉。

838794-506ddad529df4cd4.webp.jpg
搜尋微信“顧林海”公眾號,定期推送優質文章。