認識非同步、非阻塞、futrue、callback
高併發、大訪問量實際是程式猿界的分水嶺,如何從各個角度去解決這些問題?這也是面試的時候架構師被問過的最多的問題。而非同步、非阻塞對於效能的提升是每個武林高手的錦囊妙計。
非同步和非阻塞是什麼關係?什麼區別?
此問題一出,可以直接鑑別真偽,不信你問下試試~哈哈!!!看完此文,相信你就清楚了。
非同步毫無疑問,就是啟動多個執行緒,讓每個執行緒去做一部分工作,互不干擾。
當需要匯聚結果的時候,必須採用futrue的模式。簡單來講,就是當你用多執行緒非同步的去執行的時候,如果不需要知道結果,可以直接結束。但是當你需要知道結果的時候,最好採用callable和futrue配合完成。例如,如果對使用者表進行了水平切分,需要從多個表查詢資料時,就可以採用這種方式。
Future模式需要通過輪訓或阻塞等待的方式,才能得到結果。這樣總是顯得不太優雅,比較好的方式應該是callback(回撥函式,寫過ajax的肯定比較清楚)的方式,也就是執行結束的時候非同步通知完成狀態。然後再去futrue中取執行結果。
實際上futrue、callback這種經典的模型在很多語言裡都有了原生的支援,jdk中雖然有futrue,但是並不支援
非同步、非阻塞給你帶來的問題就是除錯的麻煩,程式設計複雜度的提升,不過有了這些工具類,變得簡單了很多。如果公司有開發框架的話,可以直接封裝在底層。
直接上程式碼,可以仔細看下注釋,你就明白整個過程了。
public class FutureExample {
public static void main(String[] args) throws
// jdk自帶Future模式,實現非同步,交給執行緒池處理任務
ExecutorService jdkExecutor =Executors.newSingleThreadExecutor();
Future<String> jdkFuture = jdkExecutor
.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// 模擬業務消耗時間
TimeUnit.SECONDS.sleep(100);
return "This is native future call.not supportasync callback";
}
});
// Future只實現了非同步,而沒有實現回撥.所以此時主執行緒get結果時阻塞.或者可以輪訓以便獲取非同步呼叫是否完成,提交到執行緒池到get結果之間是非阻塞的,可以處理其他任務。
System.out.println(jdkFuture.get());
// 好的實現應該是提供回撥,即非同步呼叫完成後,可以直接回調.本例採用guava提供的非同步回撥介面,方便很多.
ListeningExecutorService guavaExecutor = MoreExecutors
.listeningDecorator(Executors.newSingleThreadExecutor());
final ListenableFuture<String>listenableFuture = guavaExecutor
.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "this is guava future call.support asynccallback";
}
});
// 註冊監聽器,即非同步呼叫完成時會在指定的執行緒池中執行註冊的監聽器
listenableFuture.addListener(new Runnable() {
@Override
public void run() {
try {
System.out.println("async complete.result:"+ listenableFuture.get());
} catch (Exception e) {
}
}
}, Executors.newSingleThreadExecutor());
// 主執行緒可以繼續執行,非同步完成後會執行註冊的監聽器任務.
System.out.println("go on execute.asyn complete willcallback");
// 除了ListenableFuture,guava還提供了FutureCallback介面,相對來說更加方便一些.
ListeningExecutorService guavaExecutor2 = MoreExecutors
.listeningDecorator(Executors.newSingleThreadExecutor());
final ListenableFuture<String>listenableFuture2 = guavaExecutor2
.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
System.out.println("asyncThreadName:"
+ Thread.currentThread().getName());
return "this is guava future call.support asynccallback using FutureCallback";
}
});
// 注意這裡沒用指定執行回撥的執行緒池,從輸出可以看出,預設是和執行非同步操作的執行緒是同一個.當然也可以再起一個執行緒池,取決於處理的複雜度,和相互之間的影響。
Futures.addCallback(listenableFuture2, new FutureCallback<String>() {
@Override
public void onSuccess(String result) {
System.out
.println("async callback(using FutureCallback) result:"
+ result);
System.out.println("execute callback threadName:"
+ Thre }ad.currentThread().getName());
@Override
public void onFailure(Throwable t) {
}
});
}
}
參考文獻:
http://www.blogjava.net/landon/archive/2014/02/27/410387.html(程式碼)
http://ifeve.com/google-guava-listenablefuture/
更多文章歡迎關注我的微信公眾號,奔跑中的蝸牛,可以掃描頭像關注