Asynchronous to synchronous business requirements
Some interface query feedback results are returned asynchronously, and query results cannot be obtained immediately.
Triggers an asynchronous operation, and then passes a unique identity.
Waits until the asynchronous result returns, matching the result according to the unique identity passed in.
- How to convert to synchronous
There are a lot of normal scenarios, but sometimes you don't want to do data storage, just want to get the results of the call simply.
What if you want to achieve the results of a synchronous operation?
Ideas
Initiating an asynchronous operation
Wait until the asynchronous result returns (you can set the timeout)
- After the result is returned, the result of the asynchronous operation returns uniformly
Loop wait
query()
when the asynchronous operation is remoteCallback()
completed, it is returned synchronously.
public class Loopquery implements Async {private String result; private static final Logger Logger = Logmanager.getlogger (LoopQuery.class.getName ()); @Override public string query (string key) {Startquery (key); New Thread (New Runnable () {@Override public void run () {remotecallback (key); }}). Start (); Final String QueryResult = Endquery (); Logger.info ("Query result: {}", queryresult); return queryresult; }/** * Start query * @param key query condition */private void Startquery (final String key) {logger.info ("Execute query: {} ", key); }/** * Remote callback is waiting is random * * @param key Query condition */private void Remotecallback (final String key) {T ry {TimeUnit.SECONDS.sleep (5); } catch (Interruptedexception e) {e.printstacktrace (); } This.result = key + "-result"; Logger.info ("Remotecallback set result: {}", result); } /** * End Query * @return return result */private String endquery () {while (true) {if (null = = result) {try {TimeUnit.MILLISECONDS.sleep (100); } catch (Interruptedexception e) {e.printstacktrace (); }} else {return result; } } }}
public static void main(String[] args) { new LoopQuery().query("12345");}
18:14:16.491 [main] INFO com.github.houbb.thread.learn.aysnc.loop.LoopQuery - 执行查询: 1234518:14:21.498 [Thread-1] INFO com.github.houbb.thread.learn.aysnc.loop.LoopQuery - remoteCallback set result: 12345-result18:14:21.548 [main] INFO com.github.houbb.thread.learn.aysnc.loop.LoopQuery - 查询结果: 12345-result
Countdownlatch
Use CountDownLatch
the class to achieve the effect of synchronization.
Import Org.apache.logging.log4j.logmanager;import Org.apache.logging.log4j.logger;import Java.util.concurrent.countdownlatch;import Java.util.concurrent.timeunit;public class AsyncQuery {private static Final Logger Logger = Logmanager.getlogger (AsyncQuery.class.getName ()); /** * Result * */private String result; /** * Asynchronous to Synchronous query * @param key */public void Asyncquery (final String key) {Final Countdownlatch latch = new Countdownlatch (1); This.startquery (key); New Thread (new Runnable () {@Override public void run () {logger.info ("Remote callback thread Start"); Remotecallback (key, latch); Logger.info ("Remote Callback Thread End"); }}). Start (); try {latch.await (); } catch (Interruptedexception e) {e.printstacktrace (); } this.endquery (); } private void Startquery (final String key) {logger.info ("Execute query: {}", key); } /** * The remote callback is the wait is random * @param key */private void Remotecallback (Final String key, Countdownlatch latch) {try {TimeUnit.SECONDS.sleep (5); } catch (Interruptedexception e) {e.printstacktrace (); } This.result = key + "-result"; Latch.countdown (); } private void Endquery () {logger.info ("query result: {}", result); }}
public static void main(String[] args) { AsyncQuery asyncQuery = new AsyncQuery(); final String key = "123456"; asyncQuery.asyncQuery(key);}
18:19:12.714 [main] INFO com.github.houbb.thread.learn.aysnc.countdownlatch.AsyncQuery - 执行查询: 12345618:19:12.716 [Thread-1] INFO com.github.houbb.thread.learn.aysnc.countdownlatch.AsyncQuery - 远程回调线程开始18:19:17.720 [main] INFO com.github.houbb.thread.learn.aysnc.countdownlatch.AsyncQuery - 查询结果: 123456-result18:19:17.720 [Thread-1] INFO com.github.houbb.thread.learn.aysnc.countdownlatch.AsyncQuery - 远程回调线程结束
Spring EventListener
It is also possible to use the observer pattern. (Optimization of Scenario I)
This is used in conjunction with spring.
An object that defines a transport property.
public class BookingCreatedEvent extends ApplicationEvent { private static final long serialVersionUID = -1387078212317348344L; private String info; public BookingCreatedEvent(Object source) { super(source); } public BookingCreatedEvent(Object source, String info) { super(source); this.info = info; } public String getInfo() { return info; }}
Description: When this.context.publishEvent(bookingCreatedEvent);
triggered,
Will be @EventListener
heard by the designated method.
Import Org.springframework.beans.factory.annotation.autowired;import Org.springframework.context.applicationcontext;import Org.springframework.context.event.eventlistener;import Org.springframework.stereotype.service;import java.util.concurrent.TimeUnit; @Servicepublic class Bookingservice {@ autowired private ApplicationContext context; private volatile bookingcreatedevent bookingcreatedevent; /** * Asynchronous to Synchronous query * @param info * @return */public string asyncquery (final String info) {query (INF O); New Thread (New Runnable () {@Override public void run () {remotecallback (info); }}). Start (); while (bookingcreatedevent = = null) {//: Empty loop//short wait. try {TimeUnit.MILLISECONDS.sleep (1); } catch (Interruptedexception e) {//...} 2. Use two separate event ...} Final String result = BookingcreAtedevent.getinfo (); Bookingcreatedevent = null; return result; } @EventListener public void Onapplicationevent (Bookingcreatedevent bookingcreatedevent) {System.out.println ("Listen to remote information:" + bookingcreatedevent.getinfo ()); This.bookingcreatedevent = bookingcreatedevent; System.out.println ("After hearing the remote message:" + this.bookingCreatedEvent.getInfo ()); /** * Execute Query * @param info */public void query (final String info) {System.out.println ("Start query:") + info); }/** * Remote callback * @param info */public void Remotecallback (final String info) {System.out.println ( "Remote callback Start:" + info); try {TimeUnit.SECONDS.sleep (2); } catch (Interruptedexception e) {e.printstacktrace (); }//re-send result event String result = info + "-result"; Bookingcreatedevent bookingcreatedevent = new Bookingcreatedevent (this, result); Trigger Event This.context.publishEvent (bookingCreatedevent); }}
@RunWith(SpringJUnit4Cla***unner.class)@ContextConfiguration(classes = SpringConfig.class)public class BookServiceTest { @Autowired private BookingService bookingService; @Test public void asyncQueryTest() { bookingService.asyncQuery("1234"); }}
2018-08-10 18:27:05.958 INFO [main] com.github.houbb.spring.lean.core.ioc.event.BookingService:84 - 开始查询:12342018-08-10 18:27:05.959 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:93 - 远程回调开始:1234接收到信息: 1234-result2018-08-10 18:27:07.964 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:73 - 监听到远程的信息: 1234-result2018-08-10 18:27:07.964 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:75 - 监听到远程消息后: 1234-result2018-08-10 18:27:07.964 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:106 - 已经触发event2018-08-10 18:27:07.964 INFO [main] com.github.houbb.spring.lean.core.ioc.event.BookingService:67 - 查询结果: 1234-result2018-08-10 18:27:07.968 INFO [Thread-1] org.springframework.context.support.GenericApplicationContext:993 - Closing [email protected]ee5251: startup date [Fri Aug 10 18:27:05 CST 2018]; root of context hierarchy
Timeout and empty loop empty loop
Empty loops can cause the CPU to soar
while(true) {}
while(true) { // 小睡即可 TimeUnit.sleep(1);}
Time-out writing
It is not possible to wait for feedback and set the time-out.
/** * loops until results are obtained * @param key key * @param timeoutinseconds timeout * @param <T> generics * @return results. Throws an exception if timed out */public <T> T loopwaitforvalue (Final String key, long timeoutinseconds) {Long startTime = System.nano Time (); Long deadline = StartTime + TimeUnit.SECONDS.toNanos (timeoutinseconds); 1. If there is no new callback, or the key corresponding element does not exist. The loop is cycled while (Objectutil.isnull (Map.get (key))) {try {TimeUnit.MILLISECONDS.sleep (5); } catch (Interruptedexception e) {logger.warn ("Loop meet interruptedexception, just ignore it.", e); }//Timeout to judge long currenttime = System.nanotime (); if (currenttime >= deadline) {throw new bussinessexception (errorcode.read_time_out); }} final T target = (t) map.get (key); Logger.debug ("Loopwaitforvalue get value:{} for key:{}", Json.tojson (target), key); 2. After getting to the element, you need to remove the corresponding value map.remove (key); return target;}
Code address
Loop
Countdownlatch
Spring-event-listener
Java asynchronous query-to-sync multiple implementations: Loop wait, countdownlatch,spring even