日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

java异步处理同步化_java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring EventListener,超时处理和空循环性能优化...

發布時間:2024/7/5 javascript 29 豆豆

異步轉同步

業務需求

有些接口查詢反饋結果是異步返回的,無法立刻獲取查詢結果。

正常處理邏輯

觸發異步操作,然后傳遞一個唯一標識。

等到異步結果返回,根據傳入的唯一標識,匹配此次結果。

如何轉換為同步

正常的應用場景很多,但是有時候不想做數據存儲,只是想簡單獲取調用結果。

即想達到同步操作的結果,怎么辦呢?

思路

發起異步操作

在異步結果返回之前,一直等待(可以設置超時)

結果返回之后,異步操作結果統一返回

循環等待

LoopQuery.java

使用 query(),將異步的操作 remoteCallback() 執行完成后,同步返回。

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("查詢結果: {}", queryResult);

return queryResult;

}

/**

* 開始查詢

* @param key 查詢條件

*/

private void startQuery(final String key) {

LOGGER.info("執行查詢: {}", key);

}

/**

* 遠程的回調是等待是隨機的

*

* @param key 查詢條件

*/

private void remoteCallback(final String key) {

try {

TimeUnit.SECONDS.sleep(5);

} catch (InterruptedException e) {

e.printStackTrace();

}

this.result = key + "-result";

LOGGER.info("remoteCallback set result: {}", result);

}

/**

* 結束查詢

* @return 返回結果

*/

private String endQuery() {

while (true) {

if (null == result) {

try {

TimeUnit.MILLISECONDS.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

} else {

return result;

}

}

}

}

main()

public static void main(String[] args) {

new LoopQuery().query("12345");

}

測試結果

18:14:16.491 [main] INFO com.github.houbb.thread.learn.aysnc.loop.LoopQuery - 執行查詢: 12345

18:14:21.498 [Thread-1] INFO com.github.houbb.thread.learn.aysnc.loop.LoopQuery - remoteCallback set result: 12345-result

18:14:21.548 [main] INFO com.github.houbb.thread.learn.aysnc.loop.LoopQuery - 查詢結果: 12345-result

CountDownLatch

AsyncQuery.java

使用 CountDownLatch 類達到同步的效果。

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());

/**

* 結果

*/

private String result;

/**

* 異步轉同步查詢

* @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("遠程回調線程開始");

remoteCallback(key, latch);

LOGGER.info("遠程回調線程結束");

}

}).start();

try {

latch.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

this.endQuery();

}

private void startQuery(final String key) {

LOGGER.info("執行查詢: {}", key);

}

/**

* 遠程的回調是等待是隨機的

* @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("查詢結果: {}", result);

}

}

main()

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 - 執行查詢: 123456

18: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-result

18:19:17.720 [Thread-1] INFO com.github.houbb.thread.learn.aysnc.countdownlatch.AsyncQuery - 遠程回調線程結束

Spring EventListener

使用觀察者模式也可以。(對方案一的優化)

此處結合 spring 進行使用。

BookingCreatedEvent.java

定義一個傳輸屬性的對象。

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;

}

}

BookingService.java

說明:當 this.context.publishEvent(bookingCreatedEvent); 觸發時,

會被 @EventListener 指定的方法監聽到。

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;

@Service

public class BookingService {

@Autowired

private ApplicationContext context;

private volatile BookingCreatedEvent bookingCreatedEvent;

/**

* 異步轉同步查詢

* @param info

* @return

*/

public String asyncQuery(final String info) {

query(info);

new Thread(new Runnable() {

@Override

public void run() {

remoteCallback(info);

}

}).start();

while(bookingCreatedEvent == null) {

//.. 空循環

// 短暫等待。

try {

TimeUnit.MILLISECONDS.sleep(1);

} catch (InterruptedException e) {

//...

}

//2. 使用兩個單獨的 event...

}

final String result = bookingCreatedEvent.getInfo();

bookingCreatedEvent = null;

return result;

}

@EventListener

public void onApplicationEvent(BookingCreatedEvent bookingCreatedEvent) {

System.out.println("監聽到遠程的信息: " + bookingCreatedEvent.getInfo());

this.bookingCreatedEvent = bookingCreatedEvent;

System.out.println("監聽到遠程消息后: " + this.bookingCreatedEvent.getInfo());

}

/**

* 執行查詢

* @param info

*/

public void query(final String info) {

System.out.println("開始查詢: " + info);

}

/**

* 遠程回調

* @param info

*/

public void remoteCallback(final String info) {

System.out.println("遠程回調開始: " + info);

try {

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 重發結果事件

String result = info + "-result";

BookingCreatedEvent bookingCreatedEvent = new BookingCreatedEvent(this, result);

//觸發event

this.context.publishEvent(bookingCreatedEvent);

}

}

測試方法

@RunWith(SpringJUnit4ClassRunner.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 - 開始查詢:1234

2018-08-10 18:27:05.959 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:93 - 遠程回調開始:1234

接收到信息: 1234-result

2018-08-10 18:27:07.964 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:73 - 監聽到遠程的信息: 1234-result

2018-08-10 18:27:07.964 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:75 - 監聽到遠程消息后: 1234-result

2018-08-10 18:27:07.964 INFO [Thread-2] com.github.houbb.spring.lean.core.ioc.event.BookingService:106 - 已經觸發event

2018-08-10 18:27:07.964 INFO [main] com.github.houbb.spring.lean.core.ioc.event.BookingService:67 - 查詢結果: 1234-result

2018-08-10 18:27:07.968 INFO [Thread-1] org.springframework.context.support.GenericApplicationContext:993 - Closing org.springframework.context.support.GenericApplicationContext@5cee5251: startup date [Fri Aug 10 18:27:05 CST 2018]; root of context hierarchy

超時和空循環

空循環

空循環會導致 cpu 飆升

while(true) {

}

解決方式

while(true) {

// 小睡即可

TimeUnit.sleep(1);

}

超時編寫

不可能一直等待反饋,可以設置超時時間。

/**

* 循環等待直到獲取結果

* @param key key

* @param timeoutInSeconds 超時時間

* @param 泛型

* @return 結果。如果超時則拋出異常

*/

public T loopWaitForValue(final String key, long timeoutInSeconds) {

long startTime = System.nanoTime();

long deadline = startTime + TimeUnit.SECONDS.toNanos(timeoutInSeconds);

//1. 如果沒有新回調,或者 key 對應元素不存在。則一直循環

while(ObjectUtil.isNull(map.get(key))) {

try {

TimeUnit.MILLISECONDS.sleep(5);

} catch (InterruptedException e) {

LOGGER.warn("Loop meet InterruptedException, just ignore it.", e);

}

// 超時判斷

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. 獲取到元素之后,需要移除掉對應的值

map.remove(key);

return target;

}

代碼地址

Java異步調用轉同步的5種方式

1.異步和同步的概念 同步調用:調用方在調用過程中,持續等待返回結果. 異步調用:調用方在調用過程中,不直接等待返回結果,而是執行其他任務,結果返回形式通常為回調函數. 2 .異步轉為同步的概率 需要 ...

java 異步機制與同步機制的區別

所謂異步輸入輸出機制,是指在進行輸入輸出處理時,不必等到輸入輸出處理完畢才返回.所以異步的同義語是非阻塞(None Blocking).?網上有很多網友用很通俗的比喻 ?把同步和異步講解的很透徹 轉過 ...

異步查詢轉同步加redis業務實現的BUG分享

在最近的性能測試中,某一個查詢接口指標不通過,開發做了N次優化,最終的優化方案如下:異步查詢然后轉同步,再加上redis緩存.此為背景. 在測試過程中發現一個BUG:同樣的請求在第一次查詢結果是OK的 ...

5種必會的Java異步調用轉同步的方法你會幾種

轉載請注明本文地址:https://www.jianshu.com/p/f00aa6f66281 源碼地址:https://gitee.com/sunnymore/asyncToSync Sunny先 ...

java中全面的單例模式多種實現方式總結

單例模式的思想 想整理一些 java 并發相關的知識,不知道從哪開始,想起了單例模式中要考慮的線程安全,就從單例模式開始吧. 以前寫過單例模式,這里再重新匯總補充整理一下,單例模式的多種實現. 單例模 ...

java 多線程并發 synchronized 同步機制及方式

2. 鎖機制 3. 并發 Excutor框架 4.?并發性與多線程介紹 1. synchronized? 參考1. synchronized 分兩種方式進行線程的同步:同步塊.同步方法 1. 方法同步 ...

java異步編程降低延遲

目錄 java異步編程降低延遲 一.ExecutorService和CompletionService 二.CompletableFuture(重要) 三.stream中的parallel(并行流) ...

java筆記--關于線程同步(7種同步方式)

關于線程同步(7種方式) --如果朋友您想轉載本文章請注明轉載地址"http://www.cnblogs.com/XHJT/p/3897440.html"謝謝-- 為何要使用同步? ...

java 獲取classpath下文件多種方式

java 獲取classpath下文件多種方式 一:properties下配置 在resources下定義server.properties register.jks.path=classpath\: ...

隨機推薦

CSS3動畫事件

CSS3 的動畫效果強大,在移動端使用廣泛,動畫執行開始和結束都可以使用JS來監聽其事件. animationstart animationend 以下是一個示例 ...

oracle ebs應用產品安全性-交叉驗證規則

轉自: http://blog.itpub.net/298600/viewspace-625138/ 定義: Oracle鍵彈性域可以根據自定義鍵彈性域時所定義的規則,執行段值組合的自動交叉驗證.使用 ...

Auto Updating the exe from a network location when application starts z

http://www.codeproject.com/Tips/869588/Auto-Updating-the-exe-from-a-network-location-when?msg=499218 ...

Android+Jquery Mobile學習系列(4)-頁面跳轉及參數傳遞

關于頁面轉場,這個必須得專門列出來說明一下,因為Jquery Mobile與普通的Web發開有一些區別,這個對于新手如果不了解的話,就會鉆到死胡同.擼主前段時間就是很急躁地上手開發程序,結果在頁面轉場 ...

sql查詢統計,根據新聞類別ID統計,沒有數據顯示0

有兩張表,新聞信息表MessageInfo和新聞類別表MessageType.表結構如下: 然后需要實現下面這種查詢結果: 這個是我面試時遇到的,上面的新聞類型是亂寫的.當時沒有做出來,然后回來又研究 ...

[Linux]信號集和sigprocmask信號屏蔽函數

一.概述 系統提供這樣一種能力,就是創建一個信號集,然后傳遞給信號屏蔽函數,從而屏蔽向該進程發送的信號. 有一點需要注意的是,不能屏蔽SIGKILL和SIGSTOP信號. 信號集是sigset_t類型 ...

gitlab 502

經過一個下午的查找終于發現了錯誤,原來是在服務器上還開啟了一個tomcat服務,占用了8080端口,使GitLab的unicorn服務不能開啟. 最后在/etc/gitlab/gitlab.rb 中做 ...

P4381 [IOI2008]Island(基環樹+單調隊列優化dp)

P4381 [IOI2008]Island 題意:求圖中所有基環樹的直徑和 我們對每棵基環樹分別計算答案. 首先我們先bfs找環(dfs易爆棧) 藍后我們處理直徑 直徑不在環上,就在環上某點的子樹上 ...

Laravel JsonResponse數組獲取

有一個JsonResponse數據的格式如下: object(Illuminate\Http\JsonResponse)[474] protected 'data' => string '{&q ...

js如何切割字符串

總結

以上是生活随笔為你收集整理的java异步处理同步化_java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring EventListener,超时处理和空循环性能优化...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。