欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中將異步調(diào)用轉(zhuǎn)為同步的五種實(shí)現(xiàn)方法

 更新時(shí)間:2025年02月26日 16:40:32   作者:猿小蔡  
本文介紹了將異步調(diào)用轉(zhuǎn)為同步阻塞模式的五種方法:wait/notify、ReentrantLock+Condition、Future、CountDownLatch和CyclicBarrier,每種方法都有其適用場(chǎng)景和核心機(jī)制,可以根據(jù)具體需求選擇合適的方法,需要的朋友可以參考下

異步與同步的核心區(qū)別

  • 同步調(diào)用:調(diào)用方阻塞等待結(jié)果返回
  • 異步調(diào)用:調(diào)用方立即返回,通過回調(diào)/輪詢等方式獲取結(jié)果

本文重點(diǎn)討論如何將異步調(diào)用轉(zhuǎn)為同步阻塞模式,以下是五種實(shí)現(xiàn)方案:

方法一:使用wait/notify + synchronized

代碼示例

 public class ProducerConsumerExample {
     private static final int BUFFER_SIZE = 5;
     private final Object lock = new Object();
     private int[] buffer = new int[BUFFER_SIZE];
     private int count = 0;
 
     // 生產(chǎn)者線程
     public void produce() throws InterruptedException {
         int value = 0;
         while (true) {
             synchronized (lock) {
                 while (count == BUFFER_SIZE) {
                     System.out.println("緩沖區(qū)已滿,生產(chǎn)者等待...");
                     lock.wait();
                 }
                 buffer[count++] = value++;
                 System.out.println("生產(chǎn)數(shù)據(jù): " + value + ",緩沖區(qū)數(shù)量: " + count);
                 lock.notify();
             }
             Thread.sleep(1000);
         }
     }
 
     // 消費(fèi)者線程
     public void consume() throws InterruptedException {
         while (true) {
             synchronized (lock) {
                 while (count == 0) {
                     System.out.println("緩沖區(qū)為空,消費(fèi)者等待...");
                     lock.wait();
                 }
                 int value = buffer[--count];
                 System.out.println("消費(fèi)數(shù)據(jù): " + value + ",緩沖區(qū)數(shù)量: " + count);
                 lock.notify();
             }
             Thread.sleep(1500);
         }
     }
 
     public static void main(String[] args) {
         ProducerConsumerExample example = new ProducerConsumerExample();
     
         // 啟動(dòng)生產(chǎn)者和消費(fèi)者線程
         new Thread(example::produce).start();
         new Thread(example::consume).start();
     }
 }

關(guān)鍵要點(diǎn)

  • 共享資源保護(hù):通過synchronized(lock)?保證線程安全

  • 條件判斷:

    • ?while?循環(huán)而非if?防止虛假喚醒
    • 緩沖區(qū)滿時(shí)生產(chǎn)者等待(wait()?)
    • 緩沖區(qū)空時(shí)消費(fèi)者等待(wait()?)
  • 協(xié)作機(jī)制:每次操作后通過notify()?喚醒等待線程

  • 方法對(duì)比:

    • ?notify()?:?jiǎn)拘褑蝹€(gè)等待線程
    • ?notifyAll()?:?jiǎn)拘阉械却€程(適用于多生產(chǎn)者場(chǎng)景)

方法二:使用ReentrantLock + Condition

代碼示例

 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 
 public class TestReentrantLock4 {
     static ReentrantLock lock = new ReentrantLock();
     static Condition moneyCondition = lock.newCondition();
     static Condition ticketCondition = lock.newCondition();
     static boolean haveMoney = false;
     static boolean haveTicket = false;
 
     public static void main(String[] args) throws InterruptedException {
         // 農(nóng)民1(等錢)
         new Thread(() -> {
             lock.lock();
             try {
                 while (!haveMoney) {
                     System.out.println("農(nóng)民1等待資金...");
                     moneyCondition.await();
                 }
                 System.out.println("農(nóng)民1獲得資金,回家!");
             } finally {
                 lock.unlock();
             }
         }, "Farmer1").start();
 
         // 農(nóng)民2(等票)
         new Thread(() -> {
             lock.lock();
             try {
                 while (!haveTicket) {
                     System.out.println("農(nóng)民2等待車票...");
                     ticketCondition.await();
                 }
                 System.out.println("農(nóng)民2獲得車票,回家!");
             } finally {
                 lock.unlock();
             }
         }, "Farmer2").start();
 
         // 主線程模擬發(fā)放條件
         Thread.sleep(1000);
         lock.lock();
         try {
             haveMoney = true;
             moneyCondition.signal();
             System.out.println("資金已發(fā)放!");
 
             haveTicket = true;
             ticketCondition.signal();
             System.out.println("車票已發(fā)放!");
         } finally {
             lock.unlock();
         }
     }
 }

核心特性

  • 多條件支持:

    • 一個(gè)鎖對(duì)象可綁定多個(gè)Condition(如moneyCondition/ticketCondition)
  • 精準(zhǔn)喚醒:

    • ?await()?:釋放鎖并等待特定條件
    • ?signal()?:?jiǎn)拘褲M足條件的等待線程
  • 代碼結(jié)構(gòu):

    • 必須在lock.lock()?和finally unlock()?之間操作
    • 條件判斷使用while?循環(huán)防止虛假喚醒

方法三:Future(Callable + ExecutorService)

代碼示例

 import java.util.concurrent.*;
 
 public class FutureExample {
     public static void main(String[] args) {
         ExecutorService executor = Executors.newSingleThreadExecutor();
 
         Future<Integer> future = executor.submit(() -> {
             int sum = 0;
             for (int i = 1; i <= 100; i++) {
                 sum += i;
                 Thread.sleep(10);
             }
             return sum;
         });
 
         System.out.println("主線程執(zhí)行其他任務(wù)...");
     
         try {
             Integer result = future.get(2, TimeUnit.SECONDS);
             System.out.println("計(jì)算結(jié)果: 1+2+...+100 = " + result);
         } catch (TimeoutException e) {
             System.err.println("計(jì)算超時(shí)!");
             future.cancel(true);
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             executor.shutdown();
         }
     }
 }

關(guān)鍵API

方法作用
?future.get()?阻塞獲取結(jié)果(可設(shè)置超時(shí))
?future.cancel()?取消任務(wù)執(zhí)行
?isDone()?檢查任務(wù)是否完成

執(zhí)行流程

  • 提交Callable?任務(wù)到線程池
  • 主線程繼續(xù)執(zhí)行其他操作
  • 調(diào)用future.get()?阻塞等待結(jié)果
  • 處理可能出現(xiàn)的異常情況
  • 最終關(guān)閉線程池資源

方法四:CountDownLatch(多線程同步)

代碼示例

 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 
 public class CountDownLatchExample {
     private static final int RUNNERS = 5;
     private static final CountDownLatch startSignal = new CountDownLatch(1);
     private static final CountDownLatch readySignal = new CountDownLatch(RUNNERS);
 
     public static void main(String[] args) throws InterruptedException {
         ExecutorService executor = Executors.newFixedThreadPool(RUNNERS);
 
         for (int i = 1; i <= RUNNERS; i++) {
             executor.execute(() -> {
                 try {
                     System.out.println("運(yùn)動(dòng)員" + i + "正在準(zhǔn)備...");
                     TimeUnit.MILLISECONDS.sleep(300);
                     readySignal.countDown();
 
                     startSignal.await();
                     System.out.println("運(yùn)動(dòng)員" + i + "起跑!");
                 
                     TimeUnit.MILLISECONDS.sleep((long)(Math.random() * 1000));
                     System.out.println("運(yùn)動(dòng)員" + i + "到達(dá)終點(diǎn)!");
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             });
         }
 
         System.out.println("裁判等待運(yùn)動(dòng)員就位...");
         readySignal.await();
         System.out.println("\n所有運(yùn)動(dòng)員就位!");
 
         TimeUnit.SECONDS.sleep(1);
         System.out.println("發(fā)令槍響!");
         startSignal.countDown();
 
         executor.shutdown();
         executor.awaitTermination(5, TimeUnit.SECONDS);
         System.out.println("\n比賽結(jié)束!");
     }
 }

應(yīng)用場(chǎng)景

  • 多線程初始化后統(tǒng)一執(zhí)行:如服務(wù)啟動(dòng)時(shí)等待所有組件就緒
  • 并發(fā)測(cè)試控制:模擬固定數(shù)量請(qǐng)求同時(shí)發(fā)起
  • 事件驅(qū)動(dòng)編程:等待多個(gè)前置條件完成

方法五:CyclicBarrier(可重用同步屏障)

代碼示例

 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.CyclicBarrier;
 
 public class CyclicBarrierExample {
     private static final CyclicBarrier barrier = 
         new CyclicBarrier(3, () -> System.out.println("\n===== 進(jìn)入下一階段 ====="));
 
     public static void main(String[] args) {
         for (int i = 1; i <= 3; i++) {
             new Thread(new TeamMember(i)).start();
         }
     }
 
     static class TeamMember implements Runnable {
         private int id;
 
         public TeamMember(int id) {
             this.id = id;
         }
 
         @Override
         public void run() {
             try {
                 doWork("需求分析", 1000);
                 barrier.await();
             
                 doWork("開發(fā)編碼", 1500);
                 barrier.await();
             
                 doWork("測(cè)試部署", 800);
                 barrier.await();
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
 
         private void doWork(String phase, int baseTime) throws InterruptedException {
             int time = baseTime + (int)(Math.random() * 500);
             System.out.printf("%s 完成%s(%dms)\n", 
                 Thread.currentThread().getName(), phase, time);
             Thread.sleep(time);
         }
     }
 }

核心特性

對(duì)比項(xiàng)CountDownLatchCyclicBarrier
重用性一次性使用可重復(fù)觸發(fā)
線程關(guān)系主線程等待子線程子線程相互等待
典型場(chǎng)景線程初始化完成后執(zhí)行多階段任務(wù)協(xié)作

總結(jié)對(duì)比表

方法適用場(chǎng)景核心機(jī)制擴(kuò)展性
wait/notify簡(jiǎn)單生產(chǎn)者-消費(fèi)者模型對(duì)象鎖的等待/通知機(jī)制
ReentrantLock+Condition需要多個(gè)條件變量精細(xì)條件控制
Future異步任務(wù)結(jié)果獲取任務(wù)提交與結(jié)果回調(diào)
CountDownLatch多線程等待單一事件計(jì)數(shù)器遞減觸發(fā)機(jī)制
CyclicBarrier多階段任務(wù)同步可重置的屏障計(jì)數(shù)機(jī)制

最佳實(shí)踐建議:

  • 簡(jiǎn)單同步場(chǎng)景優(yōu)先使用CountDownLatch?
  • 需要結(jié)果返回時(shí)使用Future?
  • 多條件或多階段場(chǎng)景推薦CyclicBarrier?
  • 避免使用過時(shí)的Object.wait/notify?直接控制

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

相關(guān)文章

  • java項(xiàng)目中classpath指向哪里

    java項(xiàng)目中classpath指向哪里

    這篇文章介紹了java項(xiàng)目中classpath指向哪里及工作原理,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • 詳解Java注解的實(shí)現(xiàn)與使用方法

    詳解Java注解的實(shí)現(xiàn)與使用方法

    這篇文章主要介紹了詳解Java注解的實(shí)現(xiàn)與使用方法的相關(guān)資料,希望通過本文大家能夠理解掌握J(rèn)ava注解的知識(shí),需要的朋友可以參考下
    2017-09-09
  • Spring Boot開發(fā)編譯后讀取不到@spring.profiles.active@的問題及解決步驟

    Spring Boot開發(fā)編譯后讀取不到@spring.profiles.active@的問題及解決步驟

    這篇文章主要介紹了Spring Boot開發(fā)編譯后讀取不到@spring.profiles.active@的問題及解決步驟,需要的朋友可以參考下
    2024-12-12
  • Java實(shí)現(xiàn)接月餅小游戲的示例代碼

    Java實(shí)現(xiàn)接月餅小游戲的示例代碼

    本文將用Java語言自制一個(gè)小游戲:《接月餅小游戲》,游戲規(guī)則為不要被月亮砸到,盡可能地多接月餅。文中的實(shí)現(xiàn)代碼講解清晰,感興趣的可以動(dòng)手試一試
    2022-02-02
  • Spring?MVC DispatcherServlet處理請(qǐng)求過程示例詳解

    Spring?MVC DispatcherServlet處理請(qǐng)求過程示例詳解

    這篇文章主要介紹了Spring?MVC?DispatcherServlet處理請(qǐng)求過程示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 滴滴二面之Kafka如何讀寫副本消息的

    滴滴二面之Kafka如何讀寫副本消息的

    這篇文章主要給大家介紹了關(guān)于滴滴二面之Kafka如何讀寫副本消息的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-01-01
  • SpringBoot實(shí)現(xiàn)自定義條件注解的代碼示例

    SpringBoot實(shí)現(xiàn)自定義條件注解的代碼示例

    在Spring Boot中,條件注解是一種非常強(qiáng)大的工具,它可以根據(jù)特定的條件來選擇是否加載某個(gè)類或某個(gè)Bean,文將介紹如何在Spring Boot中實(shí)現(xiàn)自定義條件注解,并提供一個(gè)示例代碼,需要的朋友可以參考下
    2023-06-06
  • 解決springboot 無法配置多個(gè)靜態(tài)路徑的問題

    解決springboot 無法配置多個(gè)靜態(tài)路徑的問題

    這篇文章主要介紹了解決springboot 無法配置多個(gè)靜態(tài)路徑的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java使用內(nèi)存數(shù)據(jù)庫(kù)ssdb的步驟

    java使用內(nèi)存數(shù)據(jù)庫(kù)ssdb的步驟

    這篇文章主要介紹了java使用內(nèi)存數(shù)據(jù)庫(kù)ssdb的步驟,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-12-12
  • Java中泛型使用的簡(jiǎn)單方法介紹

    Java中泛型使用的簡(jiǎn)單方法介紹

    這篇文章主要給大家介紹了關(guān)于Java中泛型使用的簡(jiǎn)單方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評(píng)論