java實現異步調用實例


在JAVA平台,實現異步調用的角色有如下三個角色:
 
調用者 取貨憑證   真實數據
 
一個調用者在調用耗時操作,不能立即返回數據時,先返回一個取貨憑證.然后在過一斷時間后
憑取貨憑證來獲取真正的數據.
 
所以連結調用者和真實數據之間的橋梁是取貨憑證.我們先來看它的實現:
 
public class FutureTicket{
 private Object data = null;
 private boolean completed = false;
 
 public synchronized void makeRealData(){
  if(this.complited) return;
  //獲取數據的耗時操作.這里用Sleep代替
  try{
   Thread.sleep(10000);
  }catch(Throwable t){}
  this.data = "返回的數據內容";
  this.completed = true;
  notifyAll();
 }
 
 public synchronized Object getData(){
  while(!this.completed)){
   try{
    wait();
   }catch(Throwable t){}
  }
  return this.data;
  
 }
 public boolean isCompleted(){
  return this.completed;
 }
}
 
為了簡單化說明(不把它們的關系開得復雜),這里用Objectb代替了真實數據.而真實的實現中
我們應該把makeData放在一個真實數據的類中,然后提供一個方法返回真實數據.這樣對於真實
數據的處理和取貨憑證解耦.
 
對於這個取貨憑證,調用者的如何調用是異步調用的關鍵:
 
publc class Requester{
 public FutureTicket request(){
  final FutureTicket ft = new FutureTicket();
  
  //在新線程中調用耗時操作
  new Thread(){
   public void run(){
    ft.makeRealData();
   }
  }.start();
  return ft;
 }
}
在新線程中啟動耗時操作后,不等待線程的完成立即返回提貨單.
 
然后調用者可以根據ft.isCompleted()來調用getData()獲取真實數據.
當然對ft.isCompleted()測試可以按規定時間間隔輪巡(極低級的方案),也可以
在條件不滿足時wait(),然后等待makeData的notifyAll();這樣你就完成了一個
用JAVA模擬的異步操作.
 

改進:
但這樣的調用對於調用者來說仍然要繼續控制線程操作.如果調用者是一個資深的
程序員,這當然沒有問題.但假如我們把對直接數據的處理委托給取貨憑證來做.調用
者直接規定對數據的操作,然后由取貨憑證來調用規定的操作,這對於調用者是一個很
好的解脫:
 
interface ProcessData{
 public void process(Onject data);
}
 
public MyProcessData{
 public void process(Object data){
  //你不管什么時候起初數據data被獲取了.
  //你只要規定如果獲取到數據了如何處理
  
  System.out.println(data.toString() + "處理完成...........");
  //insert into dataBase?
 }
}
 
取貨憑證在接收調用者請求獲取數據時,要知道對獲取的數據如何處理的方法:
 
public class FutureTicket{
 private Object data = null;
 private boolean completed = false;
 private ProcessData pd;
 
 public FutureTicket(ProcessData pd){
  this.pd = pd;
 }
 public synchronized void makeRealData(ProcessData pd){
  if(this.complited) return;
  //獲取數據的耗時操作.這里用Sleep代替
  try{
   Thread.sleep(10000);
  }catch(Throwable t){}
  this.data = "返回的數據內容";
  this.completed = true;
  notifyAll();
 }
 
 public synchronized void putData(){
  while(!this.completed)){
   try{
    wait();
   }catch(Throwable t){}
  }
  //return this.data;
  //不用返回了,直接處理
  this.pd.process(this.data);
  // alert(?);
  
 }
 

 //這個方法也可以不要了.
 public boolean isCompleted(){
  return this.completed;
 }
}
 
調用:
 
  final FutureTicket ft = new FutureTicket(new ProcessData());
  
  //在新線程中調用耗時操作
  new Thread(){
   public void run(){
    ft.makeRealData();
   }
  }.start();
  ft.putData();

}

在實際編程中,往往需要網絡的異步處理。比如客戶程序,如果客戶程序運行先於服務程序,則客戶程序則需要在服務程序啟動后再自動連接服務程序;在客戶程序運行中如果服務程序中途停止,則也需要在不停止的條件下,等待服務程序運行並重新連接。下面提供了一類異步編程的方法。

  網絡異步應用涉及到如下幾個關鍵點:

 

  客戶應用啟動后,檢測服務應用是否存在。如果不存在,則等待服務應用啟動,同時不堵塞客戶應用其他任務的執行。一旦服務應用啟動,客戶應用應該及時的與其建立連接。

 

  客戶應用和服務應用在數據通信中,服務應用異常退出后,客戶應用應可以檢測到服務應用的退出。同時客戶應用自動清除該通信鏈路,回到初始狀態,等待服務應用重新啟動。

 

  該網絡異步編程首先涉及到一個定時器和定時器事件。該定時器用於不斷的檢測網絡中客戶應用和服務應用是否連通,同時在服務應用出現異常時中止數據通信,返回到初始狀態。網絡的故障可以通過網絡方法的異常處理獲知。

 

  定時器包含在網絡通信類中,使得使用該類的應用感知不到定時器的存在,而方便的處理網絡信息。

 

  該客戶程序類如下結構:

    public class NetComm 
  implements ActionListener 
  { 
      javax.swing.Timer timer = new javax.swing.Timer(3000,this); 
      Socket sock; 
      private EventNotifier en; 
      public static int net_state = 0; 
      InetAddress ServerAddr; 
      int ServerPort; 
      public NetComm(InetAddress addr, int port){ 
      ServerAddr = addr; 
      ServerPort = port; 
  } 
  public void NetComm_Init() { 
      net_state = 1; 
      try { 
          sock = new Socket(ServerAddr, ServerPort); 
      } catch (IOException e) { 
          net_state = 0; 
      } 
      timer.start(); 
  } 
  public void NetComm_Data() 
  { 
      try { 
          OutputStream outputstream = sock.getOutputStream(); 
          BufferedWriter out = new BufferedWriter 
          (new OutputStreamWriter(outputstream)); 
          out.write("java by piky2004@126.com"); 
          out.flush(); 
          BufferedReader in = new BufferedReader 
          (new InputStreamReader(sock.getInputStream())); 
          boolean more = true; 
          while(more) { 
              String str = in.readLine(); 
              if(str == null) more = false; 
              else 
              // 處理數據 
               System.out.println(str); 
          } 
      in.close(); 
      } catch (IOException e) { 
          NetComm_Close(); 
          net_state = 0; 
      } 
      timer.start(); 
  } 
  public void NetComm_Close() 
  { 
      if(sock != null) 
      try{ 
          sock.close(); 
      } catch ( IOException e) { 
      } 
  } 
  public void actionPerformed(ActionEvent e) 
  { 
      if(net_state == 0) 
      NetComm_Init(); 
      else 
      NetComm_Data(); 
  }

            

在上面的程序中,也可以為外部應用提供一個回調函數,以便在網絡異常或恢復正常時通知應用。服務應用的網絡通信類類似,可以放在同一類中。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM