当前位置: 代码网 > it编程>编程语言>Java > Java中将异步调用转为同步的五种实现方法

Java中将异步调用转为同步的五种实现方法

2025年02月26日 Java 我要评论
异步与同步的核心区别同步调用:调用方阻塞等待结果返回异步调用:调用方立即返回,通过回调/轮询等方式获取结果本文重点讨论如何将异步调用转为同步阻塞模式,以下是五种实现方案:方法一:使用wait/noti

异步与同步的核心区别

  • 同步调用:调用方阻塞等待结果返回
  • 异步调用:调用方立即返回,通过回调/轮询等方式获取结果

本文重点讨论如何将异步调用转为同步阻塞模式,以下是五种实现方案:

方法一:使用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;
 
     // 生产者线程
     public void produce() throws interruptedexception {
         int value = 0;
         while (true) {
             synchronized (lock) {
                 while (count == buffer_size) {
                     system.out.println("缓冲区已满,生产者等待...");
                     lock.wait();
                 }
                 buffer[count++] = value++;
                 system.out.println("生产数据: " + value + ",缓冲区数量: " + count);
                 lock.notify();
             }
             thread.sleep(1000);
         }
     }
 
     // 消费者线程
     public void consume() throws interruptedexception {
         while (true) {
             synchronized (lock) {
                 while (count == 0) {
                     system.out.println("缓冲区为空,消费者等待...");
                     lock.wait();
                 }
                 int value = buffer[--count];
                 system.out.println("消费数据: " + value + ",缓冲区数量: " + count);
                 lock.notify();
             }
             thread.sleep(1500);
         }
     }
 
     public static void main(string[] args) {
         producerconsumerexample example = new producerconsumerexample();
     
         // 启动生产者和消费者线程
         new thread(example::produce).start();
         new thread(example::consume).start();
     }
 }

关键要点

  • 共享资源保护:通过synchronized(lock)​保证线程安全

  • 条件判断:

    • ​while​循环而非if​防止虚假唤醒
    • 缓冲区满时生产者等待(wait()​)
    • 缓冲区空时消费者等待(wait()​)
  • 协作机制:每次操作后通过notify()​唤醒等待线程

  • 方法对比:

    • ​notify()​:唤醒单个等待线程
    • ​notifyall()​:唤醒所有等待线程(适用于多生产者场景)

方法二:使用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 {
         // 农民1(等钱)
         new thread(() -> {
             lock.lock();
             try {
                 while (!havemoney) {
                     system.out.println("农民1等待资金...");
                     moneycondition.await();
                 }
                 system.out.println("农民1获得资金,回家!");
             } finally {
                 lock.unlock();
             }
         }, "farmer1").start();
 
         // 农民2(等票)
         new thread(() -> {
             lock.lock();
             try {
                 while (!haveticket) {
                     system.out.println("农民2等待车票...");
                     ticketcondition.await();
                 }
                 system.out.println("农民2获得车票,回家!");
             } finally {
                 lock.unlock();
             }
         }, "farmer2").start();
 
         // 主线程模拟发放条件
         thread.sleep(1000);
         lock.lock();
         try {
             havemoney = true;
             moneycondition.signal();
             system.out.println("资金已发放!");
 
             haveticket = true;
             ticketcondition.signal();
             system.out.println("车票已发放!");
         } finally {
             lock.unlock();
         }
     }
 }

核心特性

  • 多条件支持:

    • 一个锁对象可绑定多个condition(如moneycondition/ticketcondition)
  • 精准唤醒:

    • ​await()​:释放锁并等待特定条件
    • ​signal()​:唤醒满足条件的等待线程
  • 代码结构:

    • 必须在lock.lock()​和finally unlock()​之间操作
    • 条件判断使用while​循环防止虚假唤醒

方法三: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("主线程执行其他任务...");
     
         try {
             integer result = future.get(2, timeunit.seconds);
             system.out.println("计算结果: 1+2+...+100 = " + result);
         } catch (timeoutexception e) {
             system.err.println("计算超时!");
             future.cancel(true);
         } catch (exception e) {
             e.printstacktrace();
         } finally {
             executor.shutdown();
         }
     }
 }

关键api

方法作用
​future.get()​阻塞获取结果(可设置超时)
​future.cancel()​取消任务执行
​isdone()​检查任务是否完成

执行流程

  • 提交callable​任务到线程池
  • 主线程继续执行其他操作
  • 调用future.get()​阻塞等待结果
  • 处理可能出现的异常情况
  • 最终关闭线程池资源

方法四: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("运动员" + i + "正在准备...");
                     timeunit.milliseconds.sleep(300);
                     readysignal.countdown();
 
                     startsignal.await();
                     system.out.println("运动员" + i + "起跑!");
                 
                     timeunit.milliseconds.sleep((long)(math.random() * 1000));
                     system.out.println("运动员" + i + "到达终点!");
                 } catch (interruptedexception e) {
                     e.printstacktrace();
                 }
             });
         }
 
         system.out.println("裁判等待运动员就位...");
         readysignal.await();
         system.out.println("\n所有运动员就位!");
 
         timeunit.seconds.sleep(1);
         system.out.println("发令枪响!");
         startsignal.countdown();
 
         executor.shutdown();
         executor.awaittermination(5, timeunit.seconds);
         system.out.println("\n比赛结束!");
     }
 }

应用场景

  • 多线程初始化后统一执行:如服务启动时等待所有组件就绪
  • 并发测试控制:模拟固定数量请求同时发起
  • 事件驱动编程:等待多个前置条件完成

方法五: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===== 进入下一阶段 ====="));
 
     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("开发编码", 1500);
                 barrier.await();
             
                 dowork("测试部署", 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);
         }
     }
 }

核心特性

对比项countdownlatchcyclicbarrier
重用性一次性使用可重复触发
线程关系主线程等待子线程子线程相互等待
典型场景线程初始化完成后执行多阶段任务协作

总结对比表

方法适用场景核心机制扩展性
wait/notify简单生产者-消费者模型对象锁的等待/通知机制
reentrantlock+condition需要多个条件变量精细条件控制
future异步任务结果获取任务提交与结果回调
countdownlatch多线程等待单一事件计数器递减触发机制
cyclicbarrier多阶段任务同步可重置的屏障计数机制

最佳实践建议:

  • 简单同步场景优先使用countdownlatch​
  • 需要结果返回时使用future​
  • 多条件或多阶段场景推荐cyclicbarrier​
  • 避免使用过时的object.wait/notify​直接控制

以上就是java中将异步调用转为同步的五种方法的详细内容,更多关于java异步调用转同步的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com