OkHttp同步請求/異步請求

同步請求

1传泊、創(chuàng)建一個請求對象

Call call = OkHttpClient.newCall(this);

2暖侨、獲取請求結(jié)果

call.execute();

Call 對象exexcute()方法分析

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    timeout.enter();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      e = timeoutExit(e);
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

在同步代碼中,先通過判斷executed標(biāo)識支竹,如果當(dāng)前已經(jīng)有在執(zhí)行,則會拋出"Already Executed"信息的異常鸠按,如果沒有執(zhí)行過礼搁,則更改executed標(biāo)識為true。一個任務(wù)只能執(zhí)行一次

captureCallStackTrace()方法:
主要用于捕捉一些http請求的異常堆棧信息

eventListener.callStart(this)方法:
開啟事件監(jiān)聽
該方法源碼

/**
   * Invoked as soon as a call is enqueued or executed by a client. In case of thread or stream
   * limits, this call may be executed well before processing the request is able to begin.
   *
   * <p>This will be invoked only once for a single {@link Call}. Retries of different routes
   * or redirects will be handled within the boundaries of a single callStart and {@link
   * #callEnd}/{@link #callFailed} pair.
   */
  public void callStart(Call call) {
  }

該方法
一旦調(diào)用被客戶端排隊或執(zhí)行目尖,就會立即調(diào)用馒吴。在線程或流受限的情況下,次調(diào)用可能在處理請求能在開始之前調(diào)用,也就是說該方法會在調(diào)用Call對象的enqueue()或execute()方法的時候饮戳,就會開啟這個listener

client.dispatcher().executed(this)方法
受限調(diào)用OkHttpClient的dispatcher()方法豪治,該方法返回一個Dispatcher對象,緊接著調(diào)用該對象的executed()方法莹捡;該方法中鬼吵,runningSyncCalls是一個存放同步請求的隊列,這里僅僅只是將RealCall加入到同步請求的隊列中

Dispatcher對象中相關(guān)的隊列有:

/** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

readyAsyncCalls 是異步請求的就緒隊列
runningAsyncCalls 是異步請求的執(zhí)行隊列
runningSyncCalls 是同步請求的執(zhí)行隊列

3篮赢、Response result = getResponseWithInterceptorChain()方法
獲取請求結(jié)果齿椅,由此可見,同步請求并沒有使用線程池
也沒有開啟子線程

4启泣、client.dispatcher().finished(this)方法
在finally中執(zhí)行
通過調(diào)用Dispatcher的finished()方法涣脚,傳入當(dāng)前的RealCall對象

/** Used by {@code Call#execute} to signal completion. */
  void finished(RealCall call) {
    finished(runningSyncCalls, 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();
    }
  }

該方法繼續(xù)調(diào)用了其他一個同名的的方法,將正在執(zhí)行的同步請求隊列傳了進(jìn)來寥茫,在同步代碼塊中遣蚀,移除掉同步請求隊列中的call對象,并進(jìn)行了判斷纱耻,如果移除出錯芭梯,則會拋出異常。接著判斷promoteCalls弄喘,由于這里傳入的promoteCalls為false玖喘,所以不會走promoteCalls()方法。

異步請求

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

client.dispatcher().enqueue(new AsyncCall(responseCallback))
調(diào)用Dispatcher的enqueue()方法蘑志,將Callback回調(diào)封裝成AsyncCall對象作為參數(shù)傳入

AsyncCall對象繼承自NamedRunnable對象累奈,而NamedRunnable對象實現(xiàn)了Runnable接口

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

該方法前加了synchronized修飾符,是一個同步方法急但,根據(jù)判斷當(dāng)前執(zhí)行的異步請求數(shù)是否小于maxRequests(最大請求數(shù)澎媒,默認(rèn)為64) 且當(dāng)前執(zhí)行的異步請求隊列中相同主機(jī)的請求數(shù)小于maxRequestsPerHost(每個主機(jī)最大請求數(shù),默認(rèn)為5) 來進(jìn)行處理波桩,如果二者都小于設(shè)置的值戒努,則將該請求添加到runningAsyncCalls(異步請求執(zhí)行隊列)中,否則則添加到readyAsyncCalls(異步請求準(zhǔn)備隊列)中镐躲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柏卤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子匀油,更是在濱河造成了極大的恐慌缘缚,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敌蚜,死亡現(xiàn)場離奇詭異桥滨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門齐媒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒲每,“玉大人,你說我怎么就攤上這事喻括⊙樱” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵唬血,是天一觀的道長望蜡。 經(jīng)常有香客問我,道長拷恨,這世上最難降的妖魔是什么脖律? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮腕侄,結(jié)果婚禮上小泉,老公的妹妹穿的比我還像新娘。我一直安慰自己冕杠,他們只是感情好微姊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著分预,像睡著了一般兢交。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上噪舀,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天魁淳,我揣著相機(jī)與錄音飘诗,去河邊找鬼与倡。 笑死,一個胖子當(dāng)著我的面吹牛昆稿,可吹牛的內(nèi)容都是我干的纺座。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼溉潭,長吁一口氣:“原來是場噩夢啊……” “哼净响!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喳瓣,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤馋贤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后畏陕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體配乓,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了犹芹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崎页。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腰埂,靈堂內(nèi)的尸體忽然破棺而出飒焦,到底是詐尸還是另有隱情,我是刑警寧澤屿笼,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布牺荠,位于F島的核電站,受9級特大地震影響刁卜,放射性物質(zhì)發(fā)生泄漏志电。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一蛔趴、第九天 我趴在偏房一處隱蔽的房頂上張望挑辆。 院中可真熱鬧,春花似錦孝情、人聲如沸鱼蝉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽魁亦。三九已至,卻和暖如春羔挡,著一層夾襖步出監(jiān)牢的瞬間洁奈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工绞灼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留利术,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓低矮,卻偏偏與公主長得像印叁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子军掂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容