java同步调用和异步调用,JAVA异步
00-1010一、问题应用场景二。分析三。实现方法I .轮询和睡眠重试机制2.wait/notify3.Lock条件4。倒计时闩锁5。环状屏障6。锁支架
目录
00-1010在应用中通过框架发送异步命令时,不能立即返回命令的执行结果,而是异步返回命令的执行结果。
那么,问题来了。对于应用中的这种异步调用,能否像同步调用一样尽快得到命令执行结果,如何实现异步转同步?
00-1010首先解释下同步和异步。
同步是指在进行调用时,在得到结果之前,调用不会返回或继续执行后续操作。异步,当发出异步过程调用时,调用者在得到结果之前可以继续执行后续操作。当这个呼叫完成时,通常通过状态、通知和回叫来通知呼叫者。对于异步调用,调用的返回不受调用者控制。
异步同步的主要实现思路:所有的实现原理都差不多,就是在调用线程中阻塞等待结果。呼叫完成后,通过回叫、设置共享状态或通知解除阻塞状态,继续后续操作。
00-1010通常在实现中,不会无限等待,会设置超时。具体超时要根据具体场景来定。
下面以回调来介绍几种常见的实现异步转同步的方法:
00-1010采用轮询和睡眠重试机制,线程会在睡眠和测试状态条件之间反复切换,直到超时或者满足状态条件,继续向下执行。这样对超时的控制是不准确的,睡眠时间需要在响应性和CPU利用率之间权衡。
私有静态long MILLIS _ OF _ WAIT _ TIME=300000 l;//等待5分钟,private final object lock=new object();//3.返回结果后回调,Unblock @ override public void回调(async response response){ synchronized(lock){//Set status condition } public result get result()抛出错误代码exception {//1。异步调用//2。阻塞并等待异步响应。current time millis()millis _ of _ wait _ time;剩余时间长=等待时间的毫秒数;//剩余等待时间while(remaining 0){ synchronized(lock){ if(状态条件未满足){ remaining=future-system . current time millis();Thread.sleep(时间和具体场景待定);}} ``````}//4.超时或结果返回正确,处理结果返回结果;}
00-1010任何Java对象都有一组监控方法(wait、notify、notifyAll等。).这些方法可以配合synchronized同步关键字实现等待/通知模式。但是,使用wait/notify使得线程的阻塞/唤醒对于线程本身来说是被动的,并且很难精确地控制哪些线程。因此,要么随机唤醒一个等待条件队列的线程(notify),要么唤醒所有线程(notifyAll,但效率很低)。当多个线程基于不同的条件在同一个条件队列上等待时,如果使用notify而不是notifyAll,很容易导致信号丢失,因此必须谨慎使用wait/notify方法。
私有静态long MILLIS _ OF _ WAIT _ TIME=300000 l;//等待5分钟,private final object lock=new object();//3.返回结果后,回调unblock @ override public void callback(asyn response){ synchronized(lock){ lock . notifyall();}公共结果getresult()抛出错误codeexception {//1。异步调用//2。阻塞并等待异步响应。current time millis()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.结果返回后进行回调,解除阻塞@Overridepublic 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.结果返回后进行回调,解除阻塞@Overridepublic 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.结果返回后进行回调,解除阻塞@Overridepublic 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.结果返回后进行回调,解除阻塞@Overridepublic 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;}
到此这篇关于详解Java中异步转同步的六种方法的文章就介绍到这了,更多相关Java异步转同步内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。