Java六种异步转同步方案,总有一款适合你

简介: Java六种异步转同步方案,总有一款适合你

一、问题



应用场景


应用中通过框架发送异步命令时,不能立刻返回命令的执行结果,而是异步返回命令的执行结果。


那么,问题来了,针对应用中这种异步调用,能不能像同步调用一样立刻获取到命令的执行结果,如何实现异步转同步?


二、分析


首先,解释下同步和异步


  • 同步,就是发出一个调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。


  • 异步,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个调用完成后,一般通过状态、通知和回调来通知调用者。


对于异步调用,调用的返回并不受调用者控制。


异步转同步主要实现思路:所有实现原理类似,是在发出调用的线程中进行阻塞等待结果,调用完成后通过回调、设置共享状态或通知进行阻塞状态的解除,继续执行后续操作。


三、实现方法


通常,实现中,不会无限的等待,一般会设定一个超时时间,具体超时时间根据具体场景确定。


下面以回调的方式介绍几种常用实现异步转同步的方法:


1.轮询与休眠重试机制


采用轮询与休眠重试机制,线程将反复在休眠和测试状态条件中之间切换,直到超时或者状态条件满足继续向下执行。这种方式,超时时间控制不准确,sleep时间需要在响应性和CPU使用率之间进行权衡。


private static long MILLIS_OF_WAIT_TIME = 300000L;// 等待时间 5分钟
private final Object lock = new Object();
//3.结果返回后进行回调,解除阻塞
@Override
public void callback(AsynResponse response){
    synchronized(lock){
        //设置状态条件
}
public Result getResult() throws ErrorCodeException {
// 1.异步调用
// 2.阻塞等待异步响应
    long future = System.currentTimeMillis() + MILLIS_OF_WAIT_TIME;
    long remaining = MILLIS_OF_WAIT_TIME;//剩余等待时间
    while(remaining > 0){
        synchronized(lock){
            if(状态条件未满足){
                remaining = future - System.currentTimeMillis();
                Thread.sleep(时间具体场景确定);
            }
        }  
````}
//4.超时或结果正确返回,对结果进行处理
    return result;
}


2.wait/notify


任意一个Java对象,都拥有一组监视器方法(wait、notify、notifyAll等方法),这些方法和synchronized同步关键字配合,可以实现等待/通知模式。但是使用wait/notify,使线程的阻塞/唤醒对线程本身来说是被动的,要准确的控制哪个线程是很困难的,所以是要么随机唤醒等待在条件队列上一个线程(notify),要么唤醒所有的(notifyAll,但是很低效)。当多个线程基于不同条件在同一条件队列上等待时,如果使用notify而不是notifyAll,很容易导致信号丢失的问题,所以必须谨慎使用wait/notify方法。


private static long MILLIS_OF_WAIT_TIME = 300000L;// 等待时间 5分钟
private final Object lock = new Object();
//3.结果返回后进行回调,解除阻塞
@Override
public void callback(AsynResponse response){
    synchronized(lock){
        lock.notifyAll();
}
public Result getResult() throws ErrorCodeException {
  // 1.异步调用
  // 2.阻塞等待异步响应
    long future = System.currentTimeMillis() + MILLIS_OF_WAIT_TIME;
    long remaining = MILLIS_OF_WAIT_TIME;//剩余等待时间
    synchronized(lock){
        while(条件未满足  && remaining > 0){ //被通知后要检查条件
            lock.wait(remaining);
            remaining = future - System.currentTimeMillis();
        }  
````}
  //4.超时或结果正确返回,对结果进行处理
    return result;
}


3.Lock Condition


使用Lock的Condition队列的实现方式和wait/notify方式类似,但是Lock支持多个Condition队列,并且支持等待状态中响应中断。


private static long SECONDS_OF_WAIT_TIME = 300L;// 等待时间 5分钟
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
//3.结果返回后进行回调,解除阻塞
@Override
public void callback(AsynResponse response){
    lock.lock();//这是前提
    try {
        condition.signal();
    }finally {
        lock.unlock();
    }
}
public Result getResult() throws ErrorCodeException {
  // 1.异步调用
  // 2.阻塞等待异步响应
    lock.lock();//这是前提
    try {
        condition.await();
    } catch (InterruptedException e) {
        //TODO
    }finally {
        lock.unlock();
    }
  //4.超时或结果正确返回,对结果进行处理
    return result;
}


4.CountDownLatch


使用CountDownLatch可以实现异步转同步,它好比计数器,在创建实例CountDownLatch对象的时候传入数字,每使用一次 countDown() 方法计数减1,当数字减到0时, await()方法后的代码将可以执行,未到0之前将一直阻塞等待。


private static long SECONDS_OF_WAIT_TIME = 300L;// 等待时间 5分钟
private final CountDownLatch countDownLatch = new CountDownLatch(1);
//3.结果返回后进行回调,解除阻塞
@Override
public void callback(AsynResponse response){
    countDownLatch.countDown();
}
public Result getResult() throws ErrorCodeException {
    // 1.异步调用
    // 2.阻塞等待异步响应
    try {
        countDownLatch.await(SECONDS_OF_WAIT_TIME, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        //TODO
    }
  //4.超时或结果正确返回,对结果进行处理
    return result;
}


5.CyclicBarrier


让一组线程达到一个屏障(也可以叫同步点)时被阻塞,直到等待最后一个线程到达屏障时,屏障才开门,所有被屏障拦截的线程才会继续执行。

每个线程通过调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前的的线程被阻塞。


private static long SECONDS_OF_WAIT_TIME = 300L;// 等待时间 5分钟
private final CountDownLatch cyclicBarrier= new CyclicBarrier(2);//设置屏障拦截的线程数为2
//3.结果返回后进行回调,解除阻塞
@Override
public void callback(AsynResponse response){
    //我也到达屏障了,可以开门了
    cyclicBarrier.await();
}
public Result getResult() throws ErrorCodeException {
    // 1.异步调用
    // 2.阻塞等待异步响应
    try {
        //我到达屏障了,还没开门,要等一等
        cyclicBarrier.await(SECONDS_OF_WAIT_TIME, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        //TODO
    }
  //4.超时或结果正确返回,对结果进行处理
    return result;
}


CountDownLatch和CyclicBarrier实现类似,区别是CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset重置,


所以CyclicBarrier能处理更为复杂的业务场景。在异步转同步中,计数器不会重用,所以使用CountDownLatch实现更适合。


6.LockSupport


LockSupport定义了一组公共静态方法,提供了最基本的线程阻塞和唤醒的方法。

private static long NANOS_OF_WAIT_TIME = 300000000L;// 等待时间 5分钟
private final LockSupport lockSupport = new LockSupport();
//3.结果返回后进行回调,解除阻塞
@Override
public void callback(AsynResponse response){
    lockSupport.unpark();
}
public Result getResult() throws ErrorCodeException {
    // 1.异步调用
    // 2.阻塞等待异步响应
    try {
        lockSupport.parkNanos(NANOS_OF_WAIT_TIME);
    } catch (InterruptedException e) {
        //TODO
    }
  //4.超时或结果正确返回,对结果进行处理
    return result;
}

今天多学一点,明天就少说一句求人的话!加油


目录
相关文章
|
13天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
65 17
|
5月前
|
Java
探索Java新境界!异步+事件驱动,打造响应式编程热潮,未来已来!
【8月更文挑战第30天】在现代软件开发中,系统响应性和可扩展性至关重要。Java作为主流编程语言,提供了多种机制如Future、CompletableFuture及事件驱动编程,有效提升应用性能。本文探讨Java异步编程模型与事件驱动编程,并介绍响应式模式,助您构建高效、灵活的应用程序。
72 3
|
26天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
145 2
|
2月前
|
Java 调度
Java 线程同步的四种方式,最全详解,建议收藏!
本文详细解析了Java线程同步的四种方式:synchronized关键字、ReentrantLock、原子变量和ThreadLocal,通过实例代码和对比分析,帮助你深入理解线程同步机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 线程同步的四种方式,最全详解,建议收藏!
|
3月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
2月前
|
JavaScript Java 中间件
Java CompletableFuture 异步超时实现探索
本文探讨了在JDK 8中`CompletableFuture`缺乏超时中断任务能力的问题,提出了一种异步超时实现方案,通过自定义工具类模拟JDK 9中`orTimeout`方法的功能,解决了任务超时无法精确控制的问题,适用于多线程并行执行优化场景。
|
3月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
66 1
|
4月前
|
Java
JAVA并发编程系列(13)Future、FutureTask异步小王子
本文详细解析了Future及其相关类FutureTask的工作原理与应用场景。首先介绍了Future的基本概念和接口方法,强调其异步计算特性。接着通过FutureTask实现了一个模拟外卖订单处理的示例,展示了如何并发查询外卖信息并汇总结果。最后深入分析了FutureTask的源码,包括其内部状态转换机制及关键方法的实现原理。通过本文,读者可以全面理解Future在并发编程中的作用及其实现细节。
|
5月前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
从0到1,手把手教你玩转Java多线程同步!
52 3
|
5月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
110 1