<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          說(shuō)實(shí)話!你知道 Java 中的回調(diào)機(jī)制嗎?

          共 13647字,需瀏覽 28分鐘

           ·

          2021-03-08 10:28

          調(diào)用和回調(diào)機(jī)制

          在一個(gè)應(yīng)用系統(tǒng)中, 無(wú)論使用何種語(yǔ)言開發(fā), 必然存在模塊之間的調(diào)用, 調(diào)用的方式分為幾種:

          1. 同步調(diào)用

          img

          同步調(diào)用是最基本并且最簡(jiǎn)單的一種調(diào)用方式, 類 A 的方法 a() 調(diào)用類 B 的方法 b(), 一直等待 b() 方法執(zhí)行完畢, a() 方法繼續(xù)往下走. 這種調(diào)用方式適用于方法 b() 執(zhí)行時(shí)間不長(zhǎng)的情況, 因?yàn)?b() 方法執(zhí)行時(shí)間一長(zhǎng)或者直接阻塞的話, a() 方法的余下代碼是無(wú)法執(zhí)行下去的, 這樣會(huì)造成整個(gè)流程的阻塞.

          2. 異步調(diào)用

          img

          異步調(diào)用是為了解決同步調(diào)用可能出現(xiàn)阻塞, 導(dǎo)致整個(gè)流程卡住而產(chǎn)生的一種調(diào)用方式. 類 A 的方法方法 a() 通過(guò)新起線程的方式調(diào)用類 B 的方法 b(), 代碼接著直接往下執(zhí)行, 這樣無(wú)論方法 b() 執(zhí)行時(shí)間多久, 都不會(huì)阻塞住方法 a() 的執(zhí)行.

          但是這種方式, 由于方法 a() 不等待方法 b() 的執(zhí)行完成, 在方法 a() 需要方法 b() 執(zhí)行結(jié)果的情況下(視具體業(yè)務(wù)而定, 有些業(yè)務(wù)比如啟異步線程發(fā)個(gè)微信通知、刷新一個(gè)緩存這種就沒(méi)必要), 必須通過(guò)一定的方式對(duì)方法 b() 的執(zhí)行結(jié)果進(jìn)行監(jiān)聽(tīng)。


          3. 回調(diào)

          如下圖所示, 回調(diào)是一種雙向的調(diào)用方式, 其實(shí)而言, 回調(diào)也有同步和異步之分, 講解中是同步回調(diào), 第二個(gè)例子使用的是異步回調(diào)

          img

          回調(diào)的思想是:

          • 類 A 的 a() 方法調(diào)用類 B 的 b() 方法
          • 類 B 的 b() 方法執(zhí)行完畢主動(dòng)調(diào)用類 A 的 callback() 方法

          通俗而言: 就是 A 類中調(diào)用 B 類中的某個(gè)方法 C, 然后 B 類中反過(guò)來(lái)調(diào)用 A 類中的方法 D, D 這個(gè)方法就叫回調(diào)方法, 這樣子說(shuō)你是不是有點(diǎn)暈暈的, 其實(shí)我剛開始也是這樣不理解, 看了人家說(shuō)比較經(jīng)典的回調(diào)方式:

          1. class A 實(shí)現(xiàn)接口 CallBack callback——背景 1
          2. class A 中包含一個(gè) class B 的引用 b ——背景 2
          3. class B 有一個(gè)參數(shù)為 callback 的方法 f(CallBack callback) ——背景 3
          4. A 的對(duì)象 a 調(diào)用 B 的方法 f(CallBack callback) ——A 類調(diào)用 B 類的某個(gè)方法 C
          5. 然后 b 就可以在 f(CallBack callback) 方法中調(diào)用 A 的方法 ——B 類調(diào)用 A 類的某個(gè)方法 D

          回調(diào)的種類

          回調(diào)分為同步回調(diào)和異步回調(diào), 假如以買彩票的場(chǎng)景來(lái)模擬, 我買彩票, 調(diào)用彩票網(wǎng), 給我返回的結(jié)果確定是否中獎(jiǎng), 同步回調(diào)就是, 我買了彩票之后, 需要等待彩票網(wǎng)給我返回的結(jié)果, 這個(gè)時(shí)候我不能做其他事情, 我必須等待這個(gè)結(jié)果, 這就叫同步回調(diào), 同步, 就意味著等待, 我不能去做其他事情, 必須等待。

          異步回調(diào)就是, 我買了彩票之后, 可以去做其他事情, 然后當(dāng)彩票網(wǎng)有了結(jié)果和消息, 再給我返回消息, 其中最明顯的方式就是在得到彩票結(jié)果的函數(shù)之中, 添加一個(gè)其他的方法, 如果我的其他方法可以立即執(zhí)行, 那么就是異步的 (給出是否中獎(jiǎng)需要花費(fèi)很長(zhǎng)的時(shí)間), 而在測(cè)試函數(shù)之中, 前后兩個(gè), 那是發(fā)生在測(cè)試函數(shù)的線程之中的, 肯定是一前一后按照次序的, 在這個(gè)地方不是顯示同步異步的地點(diǎn).

          同步回調(diào)

          同步回調(diào)和異步回調(diào), 主要體現(xiàn)在其是否需要等待. 同步調(diào)用, 如果被調(diào)用一方的 APi(第三方 API), 處理問(wèn)題需要花很長(zhǎng)時(shí)間, 我們需要等待, 那就是同步回調(diào), 如果調(diào)用完之后不需要理解得到結(jié)果, 我們調(diào)完就走, 去做其他事情, 那就是異步調(diào)用, 異步調(diào)用需要在我們調(diào)用第三方 API 處, 開啟一個(gè)新的線程即可, 而同步調(diào)用和平常的調(diào)用沒(méi)有任何區(qū)別.

          例子

          OrderResult 接口, 其中的方法 getOrderResult

          public interface OrderResult {
              /**
               * 訂購(gòu)貨物的狀態(tài)
               *
               * @param state
               * @return
               */
              //參數(shù)可以不用, 用不用按照自己的實(shí)際需求決定
              public String getOrderResult(String state);
          }

          Store 類, 商店提供會(huì)無(wú)預(yù)定消息返回的接口, 回調(diào) OrderResult 接口的方法, 給其返回預(yù)訂商品的狀態(tài), 重點(diǎn)是 returnOrderGoodsInfo(OrderResult order) 方法, 體現(xiàn)了回調(diào)的回. Store 是被調(diào)用的一方, 被調(diào)用的一方, 要回過(guò)去調(diào)用調(diào)用一方的方法, 這個(gè)方法實(shí)際上是回調(diào)接口的方法.

          public class Store {
              @Getter
              @Setter
              private String name;

              Store(String name) {
                  this.name = name;
              }

              /*回調(diào)函數(shù), 將結(jié)構(gòu)傳給那個(gè)我們不能直接調(diào)用的方法, 然后獲取結(jié)果*/
              public String returnOrderGoodsInfo(OrderResult order) {
                  String[] s = {"訂購(gòu)中...""訂購(gòu)失敗""即將發(fā)貨!""運(yùn)輸途中...""已在投遞"};
                  Random random = new Random();
                  int temp = random.nextInt(5);
                  String s1 = s[temp];
                  return order.getOrderResult(s1);
              }
          }

          SyncBuyer 類, 同步顧客類, 其中獲取商品的訂購(gòu)狀態(tài), orderGoods(), 調(diào)用了 store 返回商品調(diào)用信息的 returnOrderGoodsInfo() 方法, 但是在 Store 類的 returnOrderGoodsInfo() 方法之中, 以 OrderResult 接口為參數(shù), 反過(guò)來(lái)調(diào)用了 OrderResult 接口, 相當(dāng)于調(diào)用了其子類 SyncBuyer 本身, 以他為參數(shù), 調(diào)用了 getOrderResult(String state) 方法, 也就是 OrderResult 接口的方法, 相當(dāng)于就完成了一個(gè)調(diào)用的循環(huán), 然后取到了我們自己無(wú)法給出的結(jié)果.

          這個(gè)地方的 "循環(huán)", 是回調(diào)的關(guān)鍵所在, 需要正常調(diào)用其他外接提供方法來(lái)獲取結(jié)果的一方, 繼承一個(gè)回調(diào)接口, 實(shí)現(xiàn)它, 然后調(diào)用第三方的 API 方法, 第三方在我們調(diào)用的方法之中, 以回調(diào)結(jié)構(gòu)為參數(shù), 然后調(diào)用了接口中的方法, 其中可以返回相應(yīng)的結(jié)果給我們.

          需要說(shuō)明的是, 我們雖然實(shí)現(xiàn)了這個(gè)接口的方法, 但是我們自己的類之中, 或者說(shuō)此類本身, 卻沒(méi)法調(diào)用這個(gè)方法, 也可以說(shuō), 此類調(diào)用這個(gè)方法是不會(huì)產(chǎn)生有效的結(jié)果的. 回調(diào)的回, 就體現(xiàn)在此處, 在 Store 類之中的 returnOrderGoodsInfo(OrderResult order) 方法之中, 得到了很好的體現(xiàn).

          /*同步, 顧客在商店預(yù)訂商品, 商店通知顧客預(yù)訂情況*/
          public class SyncBuyer implements OrderResult {
              @Getter
              @Setter
              private Store store;//商店
              @Getter
              @Setter
              private String buyerName;//購(gòu)物者名
              @Getter
              @Setter
              private String goodsName;//所購(gòu)商品名

              SyncBuyer(Store store, String buyerName, String goodsName) {
                  this.store = store;
                  this.buyerName = buyerName;
                  this.goodsName = goodsName;
              }

              /*調(diào)用從商店返回訂購(gòu)物品的信息*/
              public String orderGoods() {
                  String goodsState = store.returnOrderGoodsInfo(this);
                  System.out.println(goodsState);
                  myFeeling();// 測(cè)試同步還是異步, 同步需要等待, 異步無(wú)需等待
                  return goodsState;

              }

              public void myFeeling() {
                  String[] s = {"有點(diǎn)小激動(dòng)""很期待!""希望是個(gè)好貨!"};
                  Random random = new Random();
                  int temp = random.nextInt(3);
                  System.out.println("我是" + this.getBuyerName() + ", 我現(xiàn)在的感覺(jué): " + s[temp]);
              }

              /*被回調(diào)的方法, 我們自己不去調(diào)用, 這個(gè)方法給出的結(jié)果, 是其他接口或者程序給我們的, 我們自己無(wú)法產(chǎn)生*/
              @Override
              public String getOrderResult(String state) {
                  return "在" + this.getStore().getName() + "商店訂購(gòu)的" + this.getGoodsName() + "玩具, 目前的預(yù)訂狀態(tài)是: " + state;
              }
          }

          Test2Callback 類, 測(cè)試同步回調(diào)的結(jié)果,

          public class Test2Callback {
              public static void main(String[] args) {
                  Store wallMart = new Store("沙中路沃爾瑪");
                  SyncBuyer syncBuyer = new SyncBuyer(wallMart, "小明""超能鐵扇公主");
                  System.out.println(syncBuyer.orderGoods());
              }
          }

          異步回調(diào)

          同步回調(diào)和異步回調(diào)的代碼層面的差別就是是否在我們調(diào)用第三方的 API 處, 為其開辟一條新的線程, 其他并無(wú)差異。

          例子

          OrderResult 接口, 其中的方法 getOrderResult

          public interface OrderResult {
              /**
               * 訂購(gòu)貨物的狀態(tài)
               *
               * @param state
               * @return
               */
              //參數(shù)可以不用, 用不用按照自己的實(shí)際需求決定
              public String getOrderResult(String state);
          }

          Store 類, 商店提供會(huì)無(wú)預(yù)定消息返回的接口, 回調(diào) OrderResult 接口的方法, 給其返回預(yù)訂商品的狀態(tài).

          public class Store {
              @Getter
              @Setter
              private String name;

              Store(String name) {
                  this.name = name;
              }

              /*回調(diào)函數(shù), 將結(jié)構(gòu)傳給那個(gè)我們不能直接調(diào)用的方法, 然后獲取結(jié)果*/
              public String returnOrderGoodsInfo(OrderResult order) {
                  String[] s = {"訂購(gòu)中...""訂購(gòu)失敗""即將發(fā)貨!""運(yùn)輸途中...""已在投遞"};
                  Random random = new Random();
                  int temp = random.nextInt(5);
                  String s1 = s[temp];
                  return order.getOrderResult(s1);
              }
          }

          NoSyncBuyer 類, 異步調(diào)用 Store 類的 returnOrderGoodsInfo(OrderResult order) 方法, 來(lái)返回商品轉(zhuǎn)改的結(jié)果.

          /*異步*/
          @Slf4j
          public class NoSyncBuyer implements OrderResult {
              @Getter
              @Setter
              private Store store;//商店
              @Getter
              @Setter
              private String buyerName;//購(gòu)物者名
              @Getter
              @Setter
              private String goodsName;//所購(gòu)商品名

              NoSyncBuyer(Store store, String buyerName, String goodsName) {
                  this.store = store;
                  this.buyerName = buyerName;
                  this.goodsName = goodsName;
              }

              /*調(diào)用從商店返回訂購(gòu)物品的信息*/
              public String orderGoods() {
                  String goodsState = "--";
                  MyRunnable mr = new MyRunnable();
                  Thread t = new Thread(mr);
                  t.start();
                  System.out.println(goodsState);
                  goodsState = mr.getResult();// 得到返回值
                  myFeeling();// 用來(lái)測(cè)試異步是不是還是按順序的執(zhí)行
                  return goodsState;
              }

              public void myFeeling() {
                  String[] s = {"有點(diǎn)小激動(dòng)""很期待!""希望是個(gè)好貨!"};
                  Random random = new Random();
                  int temp = random.nextInt(3);
                  System.out.println("我是" + this.getBuyerName() + ", 我現(xiàn)在的感覺(jué): " + s[temp]);
              }

              /*被回調(diào)的方法, 我們自己不去調(diào)用, 這個(gè)方法給出的結(jié)果, 是其他接口或者程序給我們的, 我們自己無(wú)法產(chǎn)生*/
              @Override
              public String getOrderResult(String state) {
                  return "在" + this.getStore().getName() + "商店訂購(gòu)的" + this.getGoodsName() + "玩具, 目前的預(yù)訂狀態(tài)是: " + state;
              }

              // 開啟另一個(gè)線程, 但是沒(méi)有返回值, 怎么回事
              // 調(diào)試的時(shí)候, 等待一會(huì)兒, 還是可以取到值, 但不是立即取到, 在print顯示的時(shí)候, 卻是null, 需要注意?
              private class MyRunnable implements Runnable {
                  @Getter
                  @Setter
                  private String result;

                  @Override
                  public void run() {
                      try {
                          Thread.sleep(10000);
                          result = store.returnOrderGoodsInfo(NoSyncBuyer.this);// 匿名函數(shù)的時(shí)候, 無(wú)法return 返回值
                      } catch (InterruptedException e) {
                          log.error("出大事了, 異步回調(diào)有問(wèn)題了", e);
                      }
                  }
              }
          }

          Test2Callback 類, 測(cè)試同步回調(diào)和異步回調(diào)的結(jié)果.

          public class Test2Callback {
              public static void main(String[] args) {
                  Store wallMart = new Store("沙中路沃爾瑪");
                  SyncBuyer syncBuyer = new SyncBuyer(wallMart, "小明""超能鐵扇公主");
                  System.out.println(syncBuyer.orderGoods());


                  System.out.println("\n");
                  Store lawson = new Store("沙中路羅森便利店");
                  NoSyncBuyer noSyncBuyer = new NoSyncBuyer(lawson, "cherry""變形金剛");
                  System.out.println(noSyncBuyer.orderGoods());
              }
          }
          作者:帶妳心菲
          來(lái)源:cnblogs.com/prayjourney/p/9667835.html

          SpringBoot啟動(dòng)時(shí)讓方法自動(dòng)執(zhí)行的幾種實(shí)現(xiàn)方式

          基于Java+Vue 實(shí)現(xiàn)的在線考試系統(tǒng)

          犧牲速度來(lái)節(jié)省內(nèi)存,Redis是覺(jué)得自己太快了嗎?

          基于SpringBoot 的CMS系統(tǒng),拿去開發(fā)企業(yè)官網(wǎng)真香

          為什么 ElasticSearch 比 MySQL 更適合復(fù)雜條件搜索

          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩免费视频一区二区 | 黄色片在线免费看 | 中文字幕第256页 | 无码人妻精品一区二区蜜桃91 | 噜噜AV在线 |