整個Netty的API都是異步的。java
下面代碼是一個簡單的回調:異步
package netty.in.action; public class Worker { public void doWork() { Fetcher fetcher = new MyFetcher(new Data(1, 0)); fetcher.fetchData(new FetcherCallback() { @Override public void onError(Throwable cause) { System.out.println("An error accour: " + cause.getMessage()); } @Override public void onData(Data data) { System.out.println("Data received: " + data); } }); } public static void main(String[] args) { Worker w = new Worker(); w.doWork(); } }
package netty.in.action; public interface Fetcher { void fetchData(FetcherCallback callback); }
package netty.in.action; public class MyFetcher implements Fetcher { final Data data; public MyFetcher(Data data){ this.data = data; } @Override public void fetchData(FetcherCallback callback) { try { callback.onData(data); } catch (Exception e) { callback.onError(e); } } }
package netty.in.action; public interface FetcherCallback { void onData(Data data) throws Exception; void onError(Throwable cause); }
package netty.in.action; public class Data { private int n; private int m; public Data(int n,int m){ this.n = n; this.m = m; } @Override public String toString() { int r = n/m; return n + "/" + m +" = " + r; } }
Fetcher.fetchData()方法需傳遞一個FetcherCallback類型的參數,當得到數據或發生錯誤時被回調。ide
FetcherCallback.onData(),將接收數據時被調用函數
FetcherCallback.onError(),發生錯誤時被調用性能
回調過程有個問題就是當你使用鏈式調用不少不一樣的方法會致使線性代碼;fetch
Futuresthis
Futures是一個抽象的概念,它表示一個值,該值可能在某一點變得可用。一個Future要麼得到計算完的結果,要麼得到計算失敗後的異常。編碼
Java在java.util.concurrent包中附帶了Future接口,它使用Executor異步執行。spa
例以下面的代碼,每傳遞一個Runnable對象到ExecutorService.submit()方法就會獲得一個回調的Future,你能使用它檢測是否執行完成。netty
package netty.in.action; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class FutureExample { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newCachedThreadPool(); Runnable task1 = new Runnable(){ @Override public void run() { //do something System.out.println("i am task1....."); } }; Callable<Integer> task2 = new Callable<Integer>() { @Override public Integer call() throws Exception { //do something return new Integer(100); } }; Future<?> f1 = executor.submit(task1); Future<Integer> f2 = executor.submit(task2); System.out.println("task1 is completed? " + f1.isDone()); System.out.println("task2 is completed? " + f2.isDone()); //waiting task1 completed while(f1.isDone()){ System.out.println("task1 completed."); break; } //waiting task2 completed while(f2.isDone()){ System.out.println("return value by task2: " + f2.get()); break; } } }
有時候使用Future感受很醜陋,由於你須要間隔檢查Future是否已完成,而使用回調會直接收到返回通知。
Netty使用以上兩種異步處理方式,提供一箭雙鵰的方案。
JAVA中:NIO2看起來很理想,可是NIO2只支持Jdk1.7+,若你的程序在Java1.6上運行,則沒法使用NIO2。
另外,Java7的NIO2中沒有提供DatagramSocket的支持,因此NIO2只支持TCP程序,不支持UDP程序。
JAVA中:ByteBuffer是一個數據容器,可是惋惜的是JDK沒有開發ByteBuffer實現的源碼;ByteBuffer容許包裝一個byte[]來得到一個實例,若是你但願儘可能減小內存拷貝,那麼這種方式是很是有用的。若果你想將ByteBuffer從新實現,那麼不要浪費你的時間了,ByteBuffer的構造函數是私有的,因此它不能被擴展。
Netty提供了本身的ByteBuffer實現,Netty經過一些簡單的APIs對ByteBuffer進行構造、使用和操做,以此來解決NIO中的一些限制。
JAVA中: NIO對緩衝區的聚合和分散操做可能會操做內存泄露。不少Channel的實現支持Gather和Scatter。這個功能容許從多個ByteBuffer中讀入或寫入到多個ByteBuffer,這樣作能夠提升性能。若是要分割的數據在多個不一樣的ByteBuffer中,使用Gather/Scatter是比較好的方式。
例如,你可能但願header在一個ByteBuffer中,而body在另外的ByteBuffer中:
下圖顯示的是Scatter(分散),將ScatteringByteBuffer中的數據分散讀取到多個ByteBuffer中:
下圖顯示的是Gather(聚合),將多個ByteBuffer的數據寫入到GatheringByteChannel:
惋惜Gather/Scatter功能會致使內存泄露,直到Java7才解決內存泄露問題。使用這個功能必須當心編碼和Java版本。