mysql异步查询 java_java 手写并发框架(一)异步查询转同步的 7 种实现方式
序言
本節將學習一下如何實現異步查詢轉同步的方式,共計介紹了 7 種常見的實現方式。
思維導圖如下:
異步轉同步
業務需求
有些接口查詢反饋結果是異步返回的,無法立刻獲取查詢結果。
比如業務開發中我們調用其他系統,但是結果的返回確實通知的。
或者 rpc 實現中,client 調用 server 端,結果也是異步返回的,那么如何同步獲取調用結果呢?
正常處理邏輯
觸發異步操作,然后傳遞一個唯一標識。
等到異步結果返回,根據傳入的唯一標識,匹配此次結果。
如何轉換為同步
正常的應用場景很多,但是有時候不想做數據存儲,只是想簡單獲取調用結果。
即想達到同步操作的結果,怎么辦呢?
思路
發起異步操作
在異步結果返回之前,一直等待(可以設置超時)
結果返回之后,異步操作結果統一返回
常見的實現方式
循環等待
wait & notify
使用條件鎖
使用 CountDownLatch
使用 CyclicBarrier
Future
Spring EventListener
下面我們一起來學習下這幾種實現方式。
循環等待
說明
循環等待是最簡單的一種實現思路。
我們調用對方一個請求,在沒有結果之前一直循環查詢即可。
這個結果可以在內存中,也可以放在 redis 緩存或者 mysql 等數據庫中。
代碼實現
定義抽象父類
為了便于后面的其他幾種實現方式統一,我們首先定義一個抽象父類。
/**
* 抽象查詢父類
* @author binbin.hou
* @since 1.0.0
*/
public abstract class AbstractQuery {
private static final Log log = LogFactory.getLog(AbstractQuery.class);
protected String result;
public void asyncToSync() {
startQuery();
new Thread(new Runnable() {
public void run() {
remoteCall();
}
}).start();
endQuery();
}
protected void startQuery() {
log.info("開始查詢...");
}
/**
* 遠程調用
*/
protected void remoteCall() {
try {
log.info("遠程調用開始");
TimeUnit.SECONDS.sleep(5);
result = "success";
log.info("遠程調用結束");
} catch (InterruptedException e) {
log.error("遠程調用失敗", e);
}
}
/**
* 查詢結束
*/
protected void endQuery() {
log.info("完成查詢,結果為:" + result);
}
}
代碼實現
實現還是非常簡單的,在沒有結果之前一直循環。
TimeUnit.MILLISECONDS.sleep(10); 這里循環等待的小睡一會兒是比較重要的,避免 cpu 飆升,也可以降低為 1ms,根據自己的業務調整即可。
/**
* 循環等待
* @author binbin.hou
* @since 1.0.0
*/
public class LoopQuery extends AbstractQuery {
private static final Log log = LogFactory.getLog(LoopQuery.class);
@Override
protected void endQuery() {
try {
while (StringUtil.isEmpty(result)) {
//循環等待一下
TimeUnit.MILLISECONDS.sleep(10);
}
//獲取結果
log.info("完成查詢,結果為:" + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
測試
LoopQuery loopQuery = new LoopQuery();
loopQuery.asyncToSync();
日志
[INFO] [2020-10-08 09:50:43.330] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 開始查詢...
[INFO] [2020-10-08 09:50:43.331] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用開始
[INFO] [2020-10-08 09:50:48.334] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用結束
[INFO] [2020-10-08 09:50:48.343] [main] [c.g.h.s.t.d.LoopQuery.endQuery] - 完成查詢,結果為:success
這里可以看到遠程調用是 Thread-0 線程執行的,遠程調用的耗時為 5S。
超時特性
為什么需要超時時間
上面的實現存在一個問題,那就是循環等待沒有超時時間。
我們的一個網絡請求,可能存在失敗,也可能對方收到請求之后沒有正確處理。
所以如果我們一直等待,可能永遠也沒有結果,或者很久之后才有結果。這在業務上是不可忍受的,所以需要添加一個超時時間。
代碼實現
/**
* 循環等待-包含超時時間
* @author binbin.hou
* @since 1.0.0
*/
public class LoopTimeoutQuery extends AbstractQuery {
private static final Log log = LogFactory.getLog(LoopTimeoutQuery.class);
/**
* 超時時間
*/
private long timeoutMills = 3000;
public LoopTimeoutQuery() {
}
public LoopTimeoutQuery(long timeoutMills) {
this.timeoutMills = timeoutMills;
}
@Override
protected void endQuery() {
try {
final long endTimeMills = System.currentTimeMillis() + timeoutMills;
while (StringUtil.isEmpty(result)) {
// 超時判斷
if(System.currentTimeMillis() >= endTimeMills) {
throw new RuntimeException("請求超時");
}
//循環等待一下
TimeUnit.MILLISECONDS.sleep(10);
}
//獲取結果
log.info("完成查詢,結果為:" + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
測試
LoopTimeoutQuery loopQuery = new LoopTimeoutQuery();
loopQuery.asyncToSync();
日志如下:
[INFO] [2020-10-08 10:04:58.091] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 開始查詢...
[INFO] [2020-10-08 10:04:58.092] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用開始
Exception in thread "main" java.lang.RuntimeException: 請求超時
at com.github.houbb.sync.test.demo.LoopTimeoutQuery.endQuery(LoopTimeoutQuery.java:38)
at com.github.houbb.sync.test.demo.AbstractQuery.asyncToSync(AbstractQuery.java:26)
at com.github.houbb.sync.test.demo.LoopTimeoutQuery.main(LoopTimeoutQuery.java:55)
[INFO] [2020-10-08 10:05:03.097] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用結束
超時時間是可以設定的,平時開發中可以根據自己的響應時間設置。
如果請求超時,考慮對應的兜底方案。
基于 wait() & notifyAll()
簡介
實際上 loop 循環還是比較消耗性能的,對于這種等待特性, jdk 實際上為我們封裝了多種特性。
比如最常見的 wait() 進入等待,notifyAll() 喚醒等待的組合方式。
這個同時也是阻塞隊列的實現思想,阻塞隊列我們就不介紹了,我們來看一下 wait+notify 的實現方式。
java 實現
package com.github.houbb.sync.test.demo;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
/**
* wait+notify 實現
* @author binbin.hou
* @since 1.0.0
*/
public class WaitNotifyQuery extends AbstractQuery {
private static final Log log = LogFactory.getLog(WaitNotifyQuery.class);
/**
* 聲明對象
*/
private final Object lock = new Object();
@Override
protected void remoteCall() {
super.remoteCall();
synchronized (lock) {
log.info("遠程線程執行完成,喚醒所有等待。");
lock.notifyAll();
}
}
@Override
protected void endQuery() {
try {
// 等待 10s
synchronized (lock) {
log.info("主線程進入等待");
lock.wait(10 * 1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
super.endQuery();
}
public static void main(String[] args) {
WaitNotifyQuery query = new WaitNotifyQuery();
query.asyncToSync();
}
}
注意:編程時需要使用 synchronized 保證鎖的持有者線程安全,不然會報錯。
測試
日志如下:
[INFO] [2020-10-08 11:05:50.769] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 開始查詢...
[INFO] [2020-10-08 11:05:50.770] [main] [c.g.h.s.t.d.WaitNotifyQuery.endQuery] - 主線程進入等待
[INFO] [2020-10-08 11:05:50.770] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用開始
[INFO] [2020-10-08 11:05:55.772] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用結束
[INFO] [2020-10-08 11:05:55.773] [Thread-0] [c.g.h.s.t.d.WaitNotifyQuery.remoteCall] - 遠程線程執行完成,喚醒所有等待。
[INFO] [2020-10-08 11:05:55.773] [main] [c.g.h.s.t.d.AbstractQuery.endQuery] - 完成查詢,結果為:success
基于條件鎖的實現
條件鎖簡介
如果你想編寫一個含有多個條件謂詞的并發對象,或者你想獲得比條件隊列的可見性之外更多的控制權,那么顯式的Lock和Condition的實現類提供了一個比內部鎖和條件隊列更加靈活的選擇。
如同Lock提供了比內部加鎖要豐富得多的特征集一樣,Condition也提供了比內部條件隊列要豐富得多的特征集:
每個鎖可以有多個等待集(因await掛起的線程的集合)、可中斷/不可中斷的條件等待、基于時限的等待以及公平/非公平隊列之間的選擇.
注意事項:
wait、notify和notifyAll在Condition對象中的對等體是await、signal和signalAll.
但是,Condition繼承與Object,這意味著它也有wait和notify方法.
一定要確保使用了正確的版本–await和signal!
java 實現
為了演示簡單,我們直接選擇可重入鎖即可。
一個Condition和一個單獨的Lock相關聯,就像條件隊列和單獨的內部鎖相關聯一樣;
調用與Condition相關聯的Lock的Lock.newCondition方法,可以創建一個Condition.
package com.github.houbb.sync.test.demo;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 條件鎖實現
* @author binbin.hou
* @since 1.0.0
*/
public class LockConditionQuery extends AbstractQuery {
private static final Log log = LogFactory.getLog(LockConditionQuery.class);
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
@Override
protected void remoteCall() {
lock.lock();
try{
super.remoteCall();
log.info("遠程線程執行完成,喚醒所有等待線程。");
condition.signalAll();
} finally {
lock.unlock();
}
}
@Override
protected void endQuery() {
lock.lock();
try{
// 等待
log.info("主線程進入等待");
condition.await();
super.endQuery();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
LockConditionQuery query = new LockConditionQuery();
query.asyncToSync();
}
}
實現也比較簡單,我們在方法進入,調用 lock.lock() 加鎖,finally 中調用 lock.unlock() 釋放鎖。
condition.await(); 進入等待;condition.signalAll(); 喚醒所有等待線程。
測試日志
[INFO] [2020-10-08 12:33:40.985] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 開始查詢...
[INFO] [2020-10-08 12:33:40.986] [main] [c.g.h.s.t.d.LockConditionQuery.endQuery] - 主線程進入等待
[INFO] [2020-10-08 12:33:40.987] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用開始
[INFO] [2020-10-08 12:33:45.990] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用結束
[INFO] [2020-10-08 12:33:45.991] [Thread-0] [c.g.h.s.t.d.LockConditionQuery.remoteCall] - 遠程線程執行完成,喚醒所有等待線程。
[INFO] [2020-10-08 12:33:45.993] [main] [c.g.h.s.t.d.AbstractQuery.endQuery] - 完成查詢,結果為:success
CountDownLatch 閉鎖實現
CountDownLatch/Future/CyclicBarrier 這三個都是 jdk 為我們提供的同步工具類,我們此處只做簡單介紹。
詳情參見:
CountDownLatch 簡介
閉鎖是一種同步工具類,可以延遲線程的進度直到其達到終止狀態。
閉鎖的作用相當于一扇門:在閉鎖到達結束狀態之前,這扇門一直是關閉的,并且沒有任何線程能通過,當到達結束狀態時,這扇門會打開并允許所有的線程通過。
當閉鎖到達結束狀態后,將不會再改變狀態,因此這扇門將永遠保持打開狀態。
閉鎖可以用來確保某些活動直到其它活動都完成后才繼續執行。
java 代碼實現
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* CountDownLatch 實現
* @author binbin.hou
* @since 1.0.0
*/
public class CountDownLatchQuery extends AbstractQuery {
private static final Log log = LogFactory.getLog(CountDownLatchQuery.class);
/**
* 閉鎖
* 調用1次,后續方法即可通行。
*/
private final CountDownLatch countDownLatch = new CountDownLatch(1);
@Override
protected void remoteCall() {
super.remoteCall();
// 調用一次閉鎖
countDownLatch.countDown();
}
@Override
protected void endQuery() {
try {
// countDownLatch.await();
countDownLatch.await(10, TimeUnit.SECONDS);
log.info("完成查詢,結果為:" + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
CountDownLatchQuery loopQuery = new CountDownLatchQuery();
loopQuery.asyncToSync();
}
}
我們在返回結果之前調用 countDownLatch.await(10, TimeUnit.SECONDS); 進行等待,這里可以指定超時時間。
remoteCall() 遠程完成后,執行一下 countDownLatch.countDown();,進而可以讓程序繼續執行下去。
測試
代碼
CountDownLatchQuery loopQuery = new CountDownLatchQuery();
loopQuery.asyncToSync();
日志
[INFO] [2020-10-08 10:24:03.348] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 開始查詢...
[INFO] [2020-10-08 10:24:03.350] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用開始
[INFO] [2020-10-08 10:24:08.353] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用結束
[INFO] [2020-10-08 10:24:08.354] [main] [c.g.h.s.t.d.CountDownLatchQuery.endQuery] - 完成查詢,結果為:success
jdk 提供的閉鎖功能還是非常的方便的。
CyclicBarrier 柵欄
簡介
柵欄(Barrier)類似于閉鎖,它能阻塞一組線程直到某個事件發生[CPJ 4.4.3]。閉鎖是一次性對象,一旦進入最終狀態,就不能被重置了。
柵欄與閉鎖的關鍵區別在于,所有線程必須同時達到柵欄位置,才能繼續執行。閉鎖用于等待事件,而柵欄用于等待其他線程。
java 實現
package com.github.houbb.sync.test.demo;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* CyclicBarrier 實現
* @author binbin.hou
* @since 1.0.0
*/
public class CyclicBarrierQuery extends AbstractQuery {
private static final Log log = LogFactory.getLog(CyclicBarrierQuery.class);
private CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
@Override
protected void remoteCall() {
super.remoteCall();
try {
cyclicBarrier.await();
log.info("遠程調用進入等待");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
@Override
protected void endQuery() {
try {
cyclicBarrier.await();
log.info("主線程進入等待");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
super.endQuery();
}
}
測試
代碼
public static void main(String[] args) {
CyclicBarrierQuery cyclicBarrierQuery = new CyclicBarrierQuery();
cyclicBarrierQuery.asyncToSync();
}
日志
[INFO] [2020-10-08 10:39:00.890] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 開始查詢...
[INFO] [2020-10-08 10:39:00.892] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用開始
[INFO] [2020-10-08 10:39:05.894] [Thread-0] [c.g.h.s.t.d.AbstractQuery.remoteCall] - 遠程調用結束
[INFO] [2020-10-08 10:39:05.895] [Thread-0] [c.g.h.s.t.d.CyclicBarrierQuery.remoteCall] - 遠程調用進入等待
[INFO] [2020-10-08 10:39:05.895] [main] [c.g.h.s.t.d.CyclicBarrierQuery.endQuery] - 主線程進入等待
[INFO] [2020-10-08 10:39:05.896] [main] [c.g.h.s.t.d.AbstractQuery.endQuery] - 完成查詢,結果為:success
可以看出遠程線程 Thread-0 執行完之后就進入等待,此時主線程調用,然后也進入等待。
等主線程 endQuery 等待時,就滿足了兩個線程同時等待,然后執行就結束了。
基于 Future 實現
Future 簡介
Future模式可以這樣來描述:我有一個任務,提交給了Future,Future替我完成這個任務。期間我自己可以去做任何想做的事情。一段時間之后,我就便可以從Future那兒取出結果。就相當于下了一張訂貨單,一段時間后可以拿著提訂單來提貨,這期間可以干別的任何事情。其中Future 接口就是訂貨單,真正處理訂單的是Executor類,它根據Future接口的要求來生產產品。
Future接口提供方法來檢測任務是否被執行完,等待任務執行完獲得結果,也可以設置任務執行的超時時間。這個設置超時的方法就是實現Java程序執行超時的關鍵。
詳細介紹:
java 代碼實現
采用 Future 返回和以前的實現差異較大,我們直接覆寫以前的方法即可。
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import java.util.concurrent.*;
/**
* Future 實現
* @author binbin.hou
* @since 1.0.0
*/
public class FutureQuery extends AbstractQuery {
private static final Log log = LogFactory.getLog(FutureQuery.class);
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
@Override
public void asyncToSync() {
//1. 開始調用
super.startQuery();
//2. 遠程調用
Future stringFuture = remoteCallFuture();
//3. 完成結果
try {
String result = stringFuture.get(10, TimeUnit.SECONDS);
log.info("調用結果:{}", result);
} catch (InterruptedException | TimeoutException | ExecutionException e) {
e.printStackTrace();
}
}
/**
* 遠程調用
* @return Future 信息
*/
private Future remoteCallFuture() {
FutureTask futureTask = new FutureTask<>(new Callable() {
@Override
public String call() throws Exception {
log.info("開始異步調用");
TimeUnit.SECONDS.sleep(5);
log.info("完成異步調用");
return "success";
}
});
executorService.submit(futureTask);
// 關閉線程池
executorService.shutdown();
return futureTask;
}
public static void main(String[] args) {
FutureQuery query = new FutureQuery();
query.asyncToSync();
}
}
遠程調用執行時,是一個 FutureTask,然后提交到線程池去執行。
獲取結果的時候,stringFuture.get(10, TimeUnit.SECONDS) 可以指定獲取的超時時間。
日志
測試日志如下:
[INFO] [2020-10-08 12:52:05.175] [main] [c.g.h.s.t.d.AbstractQuery.startQuery] - 開始查詢...
[INFO] [2020-10-08 12:52:05.177] [pool-1-thread-1] [c.g.h.s.t.d.FutureQuery.call] - 開始異步調用
[INFO] [2020-10-08 12:52:10.181] [pool-1-thread-1] [c.g.h.s.t.d.FutureQuery.call] - 完成異步調用
[INFO] [2020-10-08 12:52:10.185] [main] [c.g.h.s.t.d.FutureQuery.asyncToSync] - 調用結果:success
Spring EventListener
spring 事件監聽器模式
對于一件事情完成的結果調用,使用觀察者模式是非常適合的。
spring 為我們提供了比較強大的監聽機制,此處演示下結合 spring 使用的例子。
ps: 這個例子是2年前的自己寫的例子了,此處為了整個系列的完整性,直接搬過來作為補充。
代碼實現
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
小結
本文共計介紹了 7 種異步轉同步的方式,實際上思想都是一樣的。
在異步執行完成前等待,執行完成后喚醒等待即可。
當然我寫本文除了總結以上幾種方式以外,還想為后續寫一個異步轉同步的工具提供基礎。
下一節我們將一起學習下如何將這個功能封裝為一個同步轉換框架,感興趣的可以關注一下,便于實時接收最新內容。
覺得本文對你有幫助的話,歡迎點贊評論收藏轉發一波。你的鼓勵,是我最大的動力~
不知道你有哪些收獲呢?或者有其他更多的想法,歡迎留言區和我一起討論,期待與你的思考相遇。
代碼地址
為了便于學習,文中的所有例子都已經開源:
實現 1-6:sync
總結
以上是生活随笔為你收集整理的mysql异步查询 java_java 手写并发框架(一)异步查询转同步的 7 种实现方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL之日期时间处理函数_MySQL
- 下一篇: MYSQL查询语句待优化_mysql语句