<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>

          多線程之Exchanger

          共 6470字,需瀏覽 13分鐘

           ·

          2021-07-17 17:54

          多線程之Exchanger

          前言

          今天我們來(lái)分享最后多線程最后一個(gè)工具類組件,之后我們會(huì)繼續(xù)探索多線程的相關(guān)知識(shí):線程池、并發(fā)容器和框架,然后就是總結(jié)和查漏補(bǔ)缺。

          今天的內(nèi)容很簡(jiǎn)單,內(nèi)容也不太多,但是應(yīng)用場(chǎng)景很典型,可以解決我們實(shí)際開發(fā)中數(shù)據(jù)對(duì)比的應(yīng)用需求,好了,我們直接開始吧。

          Exchanger

          exchanger也是jdk1.5引入的,主要用來(lái)解決線程之間數(shù)據(jù)交換的問(wèn)題,和它的字面意思一樣,exchanger主要是用來(lái)交換數(shù)據(jù)的,需要注意的是,交換數(shù)據(jù)的時(shí)候只能是兩個(gè)(一對(duì))線程兩兩交換,下面我們直接看示例代碼:

          public class Example {
              private final static Exchanger<String> exchanger = new Exchanger<>();

              public static void main(String[] args) {
                  ExecutorService executorService = Executors.newFixedThreadPool(4);
                  executorService.execute(() -> {
                      String taskStr = "10只羊";
                      try {
                          System.out.println("我是task1,正在等待交換,我有" + taskStr );
                          String exchange = exchanger.exchange(taskStr);
                          System.out.println("交換完成,task1獲得:" + exchange);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });

                  executorService.execute(() -> {
                      String taskStr = "一頭牛";
                      try {
                          System.out.println("我是task2,正在等待交換,我有" + taskStr );
                          String exchange = exchanger.exchange(taskStr);
                          System.out.println("交換完成,task2獲得:" + exchange);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });

                  executorService.execute(() -> {
                      String taskStr = "50只雞";
                      try {
                          System.out.println("我是task3,正在等待交換,我有" + taskStr );
                          String exchange = exchanger.exchange(taskStr);
                          System.out.println("交換完成,task3獲得:" + exchange);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });
                  executorService.execute(() -> {
                      String taskStr = "40只鴨";
                      try {
                          System.out.println("我是task4,正在等待交換,我有" + taskStr );
                          String exchange = exchanger.exchange(taskStr);
                          System.out.println("交換完成,task4獲得:" + exchange);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });

                  executorService.shutdown();
              }
          }

          在上面的代碼中,我們定義了一個(gè)交換器Exchanger,它本身是支持泛型的,這里我們定義的是string,然后定義了一個(gè)線程池,通過(guò)線程池分別啟動(dòng)四個(gè)線程,在四個(gè)線程中,都有這樣一行代碼:

          String exchange = exchanger.exchange(taskStr);

          它的作用就是和其他線程交換數(shù)據(jù),并拿到交換后的數(shù)據(jù),然后我們運(yùn)行示例代碼:

          數(shù)據(jù)交換前,他們分別擁有10只羊,一頭牛,50只雞,40只鴨,交換后task2拿到task1的牛,task1拿到task2的羊,其他的也一樣,之所以用這個(gè)例子,是因?yàn)樗慕粨Q過(guò)程確實(shí)很像原始社會(huì)的以物易物。

          這里需要注意的是,交換數(shù)據(jù)的線程數(shù)量必須為雙數(shù),否則線程會(huì)一直被exchange方法阻塞,這里我們把最后一個(gè)線程先刪除掉,然后運(yùn)行:

          因?yàn)闆](méi)有線程再與task3進(jìn)行數(shù)據(jù)交換,所以線程被阻塞了。

          當(dāng)然有時(shí)候,阻塞并非是人為的,而是在某些特殊情況下發(fā)生,為了避免因?yàn)檫@種情況導(dǎo)致線程持續(xù)阻塞,我們可以用exchanger的另一個(gè)方法:

          這個(gè)方法支持設(shè)定超時(shí)時(shí)間,如果到設(shè)定時(shí)間依然沒(méi)有數(shù)據(jù)交換,該方法會(huì)拋出TimeoutException異常:

          關(guān)于exchanger的應(yīng)用場(chǎng)景,我能想到的就兩個(gè),一個(gè)就是數(shù)據(jù)校驗(yàn),兩個(gè)線程同時(shí)操作同一批數(shù)據(jù),我們可以對(duì)數(shù)據(jù)最終的一致性做校驗(yàn),互相驗(yàn)證,比如兩個(gè)excel的數(shù)據(jù)比對(duì);另外一個(gè)場(chǎng)景和這個(gè)很類似,就是我們?cè)趯?shí)際開發(fā)經(jīng)常會(huì)遇到方法A的運(yùn)行條件需要根據(jù)B的運(yùn)行結(jié)果進(jìn)行優(yōu)化調(diào)整,這時(shí)候我們就可以通過(guò)exchanger來(lái)來(lái)進(jìn)行數(shù)據(jù)交換,然后再繼續(xù)觸發(fā)相關(guān)操作。

          總結(jié)

          exchanger最大的優(yōu)點(diǎn)是她可以在運(yùn)行的過(guò)程中交換數(shù)據(jù),其他的應(yīng)用場(chǎng)景在遇到具體問(wèn)題的時(shí)候再進(jìn)一步分析吧。好了,exchanger的相關(guān)內(nèi)容就到這里。

          今天還要補(bǔ)充一個(gè)小知識(shí),是關(guān)于mysql的,是一個(gè)小知識(shí)點(diǎn),也是線上發(fā)現(xiàn)的一個(gè)小問(wèn)題,具體來(lái)說(shuō)就是mysql的求和語(yǔ)句,如果求和字段的值全部為null,那么最終的求和結(jié)果是null,而不是0,這樣就會(huì)有潛在的空指針異常:

          select course_type, sum(order_id) from course GROUP BY course_type

          因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">order_id都是null,所以最終sum(order_id)就是null:

          這樣如果你用包裝類接收sum(order_id)就是null,后續(xù)在操作它的時(shí)候一定要做空指針校驗(yàn),否則就是個(gè)線上bug。好了,就這么多,over

          - END -


          瀏覽 30
          點(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>
                  色香蕉视频在线 | 亚洲精品麻豆 | 国产对白在线 | 色婷婷在线播放三 | 人人看人人摸人人爱 |