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

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


目录
相关文章
|
6天前
|
Java
Java如何标记异步方法
【8月更文挑战第13天】Java如何标记异步方法
14 1
|
1月前
|
安全 Java 数据安全/隐私保护
在Java项目中集成单点登录(SSO)方案
在Java项目中集成单点登录(SSO)方案
|
1月前
|
消息中间件 Java Kafka
如何在Java中实现异步消息处理?
如何在Java中实现异步消息处理?
|
6天前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
4天前
|
前端开发 JavaScript Java
java实现异步回调返回给前端
综上,Java中实现异步回调并将结果返回给前端是一项涉及后端异步处理和前端交互的综合任务。在实际项目中,开发人员需要根据应用需求和性能预期选择合适的异步模型与工具,并进行适当的配置和优化。
18 3
|
10天前
|
Java 调度 开发者
Java并发编程:解锁多线程同步的奥秘
在Java的世界里,并发编程是提升应用性能的关键所在。本文将深入浅出地探讨Java中的并发工具和同步机制,带领读者从基础到进阶,逐步掌握多线程编程的核心技巧。通过实例演示,我们将一起探索如何在多线程环境下保持数据的一致性,以及如何有效利用线程池来管理资源。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你对Java并发编程有更深入的理解和应用。
|
13天前
|
前端开发 Java UED
java实现异步回调返回给前端
通过以上的方式,可以优雅地在Java中实现异步回调并将结果返回给前端,大大提升了应用程序的响应能力和用户体验。
25 1
|
1月前
|
Java 关系型数据库 MySQL
GraalVM 静态编译下 OTel Java Agent 的自动增强方案与实现
在 2024 OpenTelemetry Community Day 会议中,阿里云可观测工程师张乎兴(望陶)和饶子昊(铖朴)为大家带来了《GraalVM 静态编译下 OTel Java Agent 的自动增强方案与实现》的演讲分享,介绍阿里云在相关领域的探索方案,本文是相关分享对应的中文整理。
212 12
|
21天前
|
安全 Java 程序员
Java 并发编程:解锁多线程同步的奥秘
【7月更文挑战第30天】在Java的世界里,并发编程是一块充满挑战的领域。它如同一位严苛的导师,要求我们深入理解其运作机制,才能驾驭多线程的力量。本文将带你探索Java并发编程的核心概念,包括线程同步与通信、锁机制、以及并发集合的使用。我们将通过实例代码,揭示如何在多线程环境中保持数据的一致性和完整性,确保你的应用程序既高效又稳定。准备好了吗?让我们一同踏上这段解锁Java并发之谜的旅程。
26 5
|
23天前
|
安全 Java API
Java并发编程的艺术:解锁多线程同步与协作的秘密
【7月更文挑战第28天】在Java的世界中,并发编程如同一场精心编排的交响乐,每一个线程都是乐团中的乐手,而同步机制则是那指挥棒,确保旋律的和谐与统一。本文将深入探讨Java并发编程的核心概念,包括线程的创建、同步机制、以及线程间的通信方式,旨在帮助读者解锁Java多线程编程的秘密,提升程序的性能和响应性。
29 3