最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java異步調(diào)用轉(zhuǎn)同步的方法

 更新時(shí)間:2020年12月30日 08:43:18   作者:liuquanwork  
這篇文章主要介紹了Java異步調(diào)用轉(zhuǎn)同步的方法,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下

先來(lái)說(shuō)一下對(duì)異步和同步的理解:

同步調(diào)用:調(diào)用方在調(diào)用過(guò)程中,持續(xù)等待返回結(jié)果。
異步調(diào)用:調(diào)用方在調(diào)用過(guò)程中,不直接等待返回結(jié)果,而是執(zhí)行其他任務(wù),結(jié)果返回形式通常為回調(diào)函數(shù)。

其實(shí),兩者的區(qū)別還是很明顯的,這里也不再細(xì)說(shuō),我們主要來(lái)說(shuō)一下Java如何將異步調(diào)用轉(zhuǎn)為同步。換句話(huà)說(shuō),就是需要在異步調(diào)用過(guò)程中,持續(xù)阻塞至獲得調(diào)用結(jié)果。
不賣(mài)關(guān)子,先列出五種方法,然后一一舉例說(shuō)明:

  • 使用wait和notify方法
  • 使用條件鎖
  • Future
  • 使用CountDownLatch
  • 使用CyclicBarrier

1.構(gòu)造一個(gè)異步調(diào)用

首先,寫(xiě)demo需要先寫(xiě)基礎(chǔ)設(shè)施,這里的話(huà)主要是需要構(gòu)造一個(gè)異步調(diào)用模型。異步調(diào)用類(lèi):

public class AsyncCall {

  private Random random = new Random(System.currentTimeMillis());

  private ExecutorService tp = Executors.newSingleThreadExecutor();

  //demo1,2,4,5調(diào)用方法
  public void call(BaseDemo demo){

    new Thread(()->{
      long res = random.nextInt(10);

      try {
        Thread.sleep(res*1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

      demo.callback(res);
    }).start();


  }

  //demo3調(diào)用方法
  public Future<Long> futureCall(){

    return tp.submit(()-> {
      long res = random.nextInt(10);

      try {
        Thread.sleep(res*1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      return res;
    });

  }

  public void shutdown(){

    tp.shutdown();

  }

}

我們主要關(guān)心call方法,這個(gè)方法接收了一個(gè)demo參數(shù),并且開(kāi)啟了一個(gè)線(xiàn)程,在線(xiàn)程中執(zhí)行具體的任務(wù),并利用demo的callback方法進(jìn)行回調(diào)函數(shù)的調(diào)用。大家注意到了這里的返回結(jié)果就是一個(gè)[0,10)的長(zhǎng)整型,并且結(jié)果是幾,就讓線(xiàn)程sleep多久——這主要是為了更好地觀(guān)察實(shí)驗(yàn)結(jié)果,模擬異步調(diào)用過(guò)程中的處理時(shí)間。
至于futureCall和shutdown方法,以及線(xiàn)程池tp都是為了demo3利用Future來(lái)實(shí)現(xiàn)做準(zhǔn)備的。
demo的基類(lèi):

public abstract class BaseDemo {

  protected AsyncCall asyncCall = new AsyncCall();

  public abstract void callback(long response);

  public void call(){
    System.out.println("發(fā)起調(diào)用");
    asyncCall.call(this);
    System.out.println("調(diào)用返回");
  }

}

BaseDemo非常簡(jiǎn)單,里面包含一個(gè)異步調(diào)用類(lèi)的實(shí)例,另外有一個(gè)call方法用于發(fā)起異步調(diào)用,當(dāng)然還有一個(gè)抽象方法callback需要每個(gè)demo去實(shí)現(xiàn)的——主要在回調(diào)中進(jìn)行相應(yīng)的處理來(lái)達(dá)到異步調(diào)用轉(zhuǎn)同步的目的。

2. 使用wait和notify方法

這個(gè)方法其實(shí)是利用了鎖機(jī)制,直接貼代碼:

public class Demo1 extends BaseDemo{

  private final Object lock = new Object();

  @Override
  public void callback(long response) {
    System.out.println("得到結(jié)果");
    System.out.println(response);
    System.out.println("調(diào)用結(jié)束");

    synchronized (lock) {
      lock.notifyAll();
    }

  }

  public static void main(String[] args) {

    Demo1 demo1 = new Demo1();

    demo1.call();

    synchronized (demo1.lock){
      try {
        demo1.lock.wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    System.out.println("主線(xiàn)程內(nèi)容");

  }
}

可以看到在發(fā)起調(diào)用后,主線(xiàn)程利用wait進(jìn)行阻塞,等待回調(diào)中調(diào)用notify或者notifyAll方法來(lái)進(jìn)行喚醒。注意,和大家認(rèn)知的一樣,這里wait和notify都是需要先獲得對(duì)象的鎖的。在主線(xiàn)程中最后我們打印了一個(gè)內(nèi)容,這也是用來(lái)驗(yàn)證實(shí)驗(yàn)結(jié)果的,如果沒(méi)有wait和notify,主線(xiàn)程內(nèi)容會(huì)緊隨調(diào)用內(nèi)容立刻打印;而像我們上面的代碼,主線(xiàn)程內(nèi)容會(huì)一直等待回調(diào)函數(shù)調(diào)用結(jié)束才會(huì)進(jìn)行打印。
沒(méi)有使用同步操作的情況下,打印結(jié)果:

發(fā)起調(diào)用
調(diào)用返回
主線(xiàn)程內(nèi)容
得到結(jié)果
1
調(diào)用結(jié)束

而使用了同步操作后:

發(fā)起調(diào)用
調(diào)用返回
得到結(jié)果
9
調(diào)用結(jié)束
主線(xiàn)程內(nèi)容

3. 使用條件鎖

和方法一的原理類(lèi)似:

public class Demo2 extends BaseDemo {

  private final Lock lock = new ReentrantLock();
  private final Condition con = lock.newCondition();

  @Override
  public void callback(long response) {

    System.out.println("得到結(jié)果");
    System.out.println(response);
    System.out.println("調(diào)用結(jié)束");
    lock.lock();
    try {
      con.signal();
    }finally {
      lock.unlock();
    }

  }

  public static void main(String[] args) {

    Demo2 demo2 = new Demo2();

    demo2.call();

    demo2.lock.lock();

    try {
      demo2.con.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }finally {
      demo2.lock.unlock();
    }
    System.out.println("主線(xiàn)程內(nèi)容");
  }
}

基本上和方法一沒(méi)什么區(qū)別,只是這里使用了條件鎖,兩者的鎖機(jī)制有所不同。

4. Future

使用Future的方法和之前不太一樣,我們調(diào)用的異步方法也不一樣。

public class Demo3{

  private AsyncCall asyncCall = new AsyncCall();

  public Future<Long> call(){

    Future<Long> future = asyncCall.futureCall();

    asyncCall.shutdown();

    return future;

  }

  public static void main(String[] args) {

    Demo3 demo3 = new Demo3();

    System.out.println("發(fā)起調(diào)用");
    Future<Long> future = demo3.call();
    System.out.println("返回結(jié)果");

    while (!future.isDone() && !future.isCancelled());

    try {
      System.out.println(future.get());
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }

    System.out.println("主線(xiàn)程內(nèi)容");

  }
}

我們調(diào)用futureCall方法,方法中會(huì)想線(xiàn)程池tp提交一個(gè)Callable,然后返回一個(gè)Future,這個(gè)Future就是我們demo3中call中得到的,得到future對(duì)象之后就可以關(guān)閉線(xiàn)程池啦,調(diào)用asyncCall的shutdown方法。關(guān)于關(guān)閉線(xiàn)程池這里有一點(diǎn)需要注意,我們回過(guò)頭來(lái)看看asyncCall的shutdown方法:

public void shutdown(){

    tp.shutdown();

  }

發(fā)現(xiàn)只是簡(jiǎn)單調(diào)用了線(xiàn)程池的shutdown方法,然后我們說(shuō)注意的點(diǎn),這里最好不要用tp的shutdownNow方法,該方法會(huì)試圖去中斷線(xiàn)程中中正在執(zhí)行的任務(wù);也就是說(shuō),如果使用該方法,有可能我們的future所對(duì)應(yīng)的任務(wù)將被中斷,無(wú)法得到執(zhí)行結(jié)果。
然后我們關(guān)注主線(xiàn)程中的內(nèi)容,主線(xiàn)程的阻塞由我們自己來(lái)實(shí)現(xiàn),通過(guò)future的isDone和isCancelled來(lái)判斷執(zhí)行狀態(tài),一直到執(zhí)行完成或被取消。隨后,我們打印get到的結(jié)果。

5. 使用CountDownLatch

使用CountDownLatch或許是日常編程中最常見(jiàn)的一種了,也感覺(jué)是相對(duì)優(yōu)雅的一種:

public class Demo4 extends BaseDemo{

  private final CountDownLatch countDownLatch = new CountDownLatch(1);

  @Override
  public void callback(long response) {

    System.out.println("得到結(jié)果");
    System.out.println(response);
    System.out.println("調(diào)用結(jié)束");

    countDownLatch.countDown();

  }

  public static void main(String[] args) {

    Demo4 demo4 = new Demo4();

    demo4.call();

    try {
      demo4.countDownLatch.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println("主線(xiàn)程內(nèi)容");

  }
}

正如大家平時(shí)使用的那樣,此處在主線(xiàn)程中利用CountDownLatch的await方法進(jìn)行阻塞,在回調(diào)中利用countDown方法來(lái)使得其他線(xiàn)程await的部分得以繼續(xù)運(yùn)行。
當(dāng)然,這里和demo1和demo2中都一樣,主線(xiàn)程中阻塞的部分,都可以設(shè)置一個(gè)超時(shí)時(shí)間,超時(shí)后可以不再阻塞。

6. 使用CyclicBarrier

CyclicBarrier的情況和CountDownLatch有些類(lèi)似:

public class Demo5 extends BaseDemo{

  private CyclicBarrier cyclicBarrier = new CyclicBarrier(2);


  @Override
  public void callback(long response) {

    System.out.println("得到結(jié)果");
    System.out.println(response);
    System.out.println("調(diào)用結(jié)束");

    try {
      cyclicBarrier.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (BrokenBarrierException e) {
      e.printStackTrace();
    }

  }

  public static void main(String[] args) {

    Demo5 demo5 = new Demo5();

    demo5.call();

    try {
      demo5.cyclicBarrier.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (BrokenBarrierException e) {
      e.printStackTrace();
    }

    System.out.println("主線(xiàn)程內(nèi)容");

  }
}

大家注意一下,CyclicBarrier和CountDownLatch僅僅只是類(lèi)似,兩者還是有一定區(qū)別的。比如,一個(gè)可以理解為做加法,等到加到這個(gè)數(shù)字后一起運(yùn)行;一個(gè)則是減法,減到0繼續(xù)運(yùn)行。一個(gè)是可以重復(fù)計(jì)數(shù)的;另一個(gè)不可以等等等等。
另外,使用CyclicBarrier的時(shí)候要注意兩點(diǎn)。第一點(diǎn),初始化的時(shí)候,參數(shù)數(shù)字要設(shè)為2,因?yàn)楫惒秸{(diào)用這里是一個(gè)線(xiàn)程,而主線(xiàn)程是一個(gè)線(xiàn)程,兩個(gè)線(xiàn)程都await的時(shí)候才能繼續(xù)執(zhí)行,這也是和CountDownLatch區(qū)別的部分。第二點(diǎn),也是關(guān)于初始化參數(shù)的數(shù)值的,和這里的demo無(wú)關(guān),在平時(shí)編程的時(shí)候,需要比較小心,如果這個(gè)數(shù)值設(shè)置得很大,比線(xiàn)程池中的線(xiàn)程數(shù)都大,那么就很容易引起死鎖了。

總結(jié)

綜上,就是本次需要說(shuō)的幾種方法了。事實(shí)上,所有的方法都是同一個(gè)原理,也就是在調(diào)用的線(xiàn)程中進(jìn)行阻塞等待結(jié)果,而在回調(diào)中函數(shù)中進(jìn)行阻塞狀態(tài)的解除。

以上就是Java異步調(diào)用轉(zhuǎn)同步的方法的詳細(xì)內(nèi)容,更多關(guān)于Java異步調(diào)用轉(zhuǎn)同步的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot實(shí)現(xiàn)文件的上傳、下載和預(yù)覽功能

    SpringBoot實(shí)現(xiàn)文件的上傳、下載和預(yù)覽功能

    在Spring Boot項(xiàng)目中實(shí)現(xiàn)文件的上傳、下載和預(yù)覽功能,可以通過(guò)使用Spring MVC的MultipartFile接口來(lái)處理文件上傳,并使用HttpServletResponse或Resource來(lái)實(shí)現(xiàn)文件下載和預(yù)覽,下面是如何實(shí)現(xiàn)這些功能的完整示例,需要的朋友可以參考下
    2024-08-08
  • java 對(duì)象的克?。\克隆和深克?。? src=

    java 對(duì)象的克?。\克隆和深克隆)

    這篇文章主要介紹了java 對(duì)象的克隆的相關(guān)資料,這里對(duì)淺克隆和深克隆進(jìn)行了實(shí)例分析需要的朋友可以參考下
    2017-07-07
  • java微信server錄音下載到自己server

    java微信server錄音下載到自己server

    這篇文章主要為大家詳細(xì)介紹了java微信server錄音下載到自己server的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 淺談DetachedCriteria和Criteria的使用方法(必看)

    淺談DetachedCriteria和Criteria的使用方法(必看)

    下面小編就為大家?guī)?lái)一篇淺談DetachedCriteria和Criteria的使用方法(必看)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • Java中對(duì)象序列化與反序列化詳解

    Java中對(duì)象序列化與反序列化詳解

    這篇文章主要介紹了Java中對(duì)象序列化與反序列化,較為詳細(xì)的分析了java中對(duì)象序列化的概念、原理、實(shí)現(xiàn)方法及相關(guān)注意事項(xiàng),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09
  • java字符串的重要使用方法以及實(shí)例

    java字符串的重要使用方法以及實(shí)例

    在本篇文章里小編給大家整理了關(guān)于java字符串的重要使用方法以及實(shí)例代碼,需要的朋友們可以跟著學(xué)習(xí)參考下。
    2019-03-03
  • springboot集成springCloud中g(shù)ateway時(shí)啟動(dòng)報(bào)錯(cuò)的解決

    springboot集成springCloud中g(shù)ateway時(shí)啟動(dòng)報(bào)錯(cuò)的解決

    這篇文章主要介紹了springboot集成springCloud中g(shù)ateway時(shí)啟動(dòng)報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringCloud分布式鏈路跟蹤的方法

    SpringCloud分布式鏈路跟蹤的方法

    這篇文章主要介紹了SpringCloud分布式鏈路跟蹤的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-03-03
  • SpringBoot實(shí)現(xiàn)接口的各種參數(shù)校驗(yàn)的示例

    SpringBoot實(shí)現(xiàn)接口的各種參數(shù)校驗(yàn)的示例

    本文主要介紹了SpringBoot實(shí)現(xiàn)接口的各種參數(shù)校驗(yàn)的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Spring注解中@Autowired和@Bean的區(qū)別詳解

    Spring注解中@Autowired和@Bean的區(qū)別詳解

    這篇文章主要詳細(xì)介紹了Spring注解中@Autowired和@Bean二者有什么區(qū)別,文中通過(guò)兩個(gè)注解的使用場(chǎng)景介紹了二者的區(qū)別,感興趣的同學(xué)可以參考閱讀
    2023-06-06

最新評(píng)論

长子县| 莲花县| 乌鲁木齐市| 和林格尔县| 封丘县| 松滋市| 井冈山市| 祁东县| 襄城县| 新沂市| 南宫市| 伊吾县| 始兴县| 石楼县| 松潘县| 来凤县| 于田县| 顺昌县| 镇远县| 同江市| 大新县| 安溪县| 道孚县| SHOW| 长垣县| 聂荣县| 四子王旗| 红安县| 韩城市| 武宁县| 诸城市| 泸州市| 泽库县| 阿克苏市| 乡宁县| 温州市| 太湖县| 毕节市| 金阳县| 仁怀市| 天峨县|