java回撥原理,以及Callable和FutureTask通過回撥機制建立可監控的執行緒
回撥的概念會JS的人應該都能理解。
回撥分非同步回撥,同步回撥。但是同步回撥其實沒什麼意義。都同步了,那麼直接等那邊執行完了,這邊再執行就可以了,沒必要通過回撥。我們說的回撥主要是講非同步回撥。用於兩個執行緒甚至兩個系統之間互動呼叫。
例如我在A類的方法funa()中,要呼叫B類的方法funb(),如果B類的方法會執行很久,但是A類方法中又還有部分後續任務需要等B執行完後才執行,又不願意傻等B類方法執行完,怎麼辦?
解決辦法:
1,把需要等待B類執行完才能執行的後續任務放到一個方法中,把方法封裝到一個類裡面(也可以就放在A類裡面)。A類方法在呼叫
2,在B類方法中,新建一個執行緒,讓這個方法慢慢執行,關鍵是執行完了之後。B類方法中呼叫一下A類的封裝的這個後續方法。
這就是回調了,大致的概念如此,具體的實現還是有些區別,比如通常實際中,不是要B把A的後續任務作了,B只需要呼叫回撥方法通知A做完了。我們回撥方法,做成一個介面。讓B類的入參是這個介面類。讓A類實現這個介面並重寫回調方法。
JAVA方法回撥是功能定義和功能實現分享的一種手段,是一種耦合設計思想。作為一種架構,必須有自己的執行環境,並且提供使用者的實現介面。
因為方法的回撥是通過介面來實現的所以要定義一個介面
Callable
我們知道執行緒執行的時候,是執行Runnable實現類的重寫的void run()方法。
new Thread(new Runnable(){public void run(){…}}).start();
這個方法是沒有返回值的。所以線上程結束之後,無法獲取執行結果。(雖然也可以通過共享變數,和執行緒通訊等方式來獲取,但是比較麻煩)
如果想要執行緒執行有返回值,並且可以在一定程度上跟蹤操作執行緒,那怎麼辦呢?於是就有了Callable和FutureTask。
Future就是對於具體的Runnable或者Callable任務的執行結果進行取消boolean
FutureTask是一個RunnableFuture<V>,而RunnableFuture實現了Runnbale又實現了Futrue<V>這兩個介面。所以可以作為一個回撥介面類,也可以作為執行緒的執行任務類。為了能夠獲取執行緒狀態,那麼執行方法肯定有一些相應的改動。在FutureTask的run方法中,我們不再是執行的具體任務,而是呼叫回撥介面的實現方法,call(),並且監控call的執行情況,設定各種狀態引數。其區域性程式碼如下圖所示:
這裡只是區域性的一些控制,還有一些狀態引數,我也看得不是太懂- -!總之正如上文所說,執行緒真正要實現的任務放在了回撥函式call()中並且可以設定返回值,Future中的run主要是對回撥函式的呼叫,以及對回撥函式執行狀態的監視,以便在其他方法中(isDone,cancel)判斷執行緒執行狀態或者暫停執行緒時用到。
知道了,這些,我們要設計一個demo就ihen簡單了,程式碼如下:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* Created by tanjun on 2018/11/30.
*/
public class CallBakTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("通過callable和future方式啟動執行緒。");
Callable callf= new Callable<Map>(){ //使用map作為返回值,包含狀態碼
@Override
public Map call() throws Exception {
Map m=new HashMap();
try {
Thread.sleep(1000);//執行緒要執行的任務
m.put("code","1");//返回的執行狀態-成功
m.put("msg",Thread.currentThread().getName()+"執行成功!");//返回的附帶訊息
}catch(Exception e){
m.put("code","0");//返回的執行狀態-成功
m.put("msg",Thread.currentThread().getName()+"執行失敗!");//返回的附帶訊息
}
return m;
}
};
FutureTask<Map> future=new FutureTask<>(callf);
new Thread(future).start();
System.out.println("主執行緒可以做其他事情...此時主執行緒事不需要阻塞的。");
//接下來主執行緒要做根據子執行緒結果做相關的事情,這個時候,就可以阻塞等子執行緒執行完了。
Map result= future.get();
if("1".equals(result.get("code").toString())){
System.out.println(result.get("msg"));
}else{
System.out.println(result.get("msg"));
}
}
}