Java多线程实现异步调用

原文地址:http://blog.sina.com.cn/s/blog_4cc16fc50100c0aa.html

在JAVA平台,实现异步调用的角色有如下三个角色:调用者  提货单      真实数据
一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单.然后在过一断时间后凭提货单来获取真正的数据.
去蛋糕店买蛋糕,不需要等蛋糕做出来(假设现做要很长时间),只需要领个提货单就可以了(去干别的事情),等到蛋糕做好了,再拿提货单取蛋糕就可以了。
public class Main {   
  1.     public static void main(String[] args) {   
  2.         System.out.println("main BEGIN");   
  3.         Host host new Host();   
  4.         //Data data1 host.request(10'A');   
  5.         //Data data2 host.request(20'B');   
  6.         //Data data3 host.request(30'C');  
  7.        //原来的代码会报错,取不到getContent() ,改为如下代码
  8.          FutureData data1 =host.request(10, 'A');   
         FutureData data2 = host.request(20, 'B');   
         FutureData data3 = host.request(30, 'C');

  9.         System.out.println("main otherJob BEGIN");   
  10.         try {   
  11.             Thread.sleep(200);   
  12.         catch (InterruptedException e) {   
  13.         }   
  14.         System.out.println("main otherJob END");   
  15.   
  16.         System.out.println("data1 " data1.getContent());   
  17.         System.out.println("data2 " data2.getContent());   
  18.         System.out.println("data3 " data3.getContent());   
  19.         System.out.println("main END");   
  20.     }   
  21.  
  这里的main类就相当于“顾客”,host就相当于“蛋糕店”,顾客向“蛋糕店”定蛋糕就相当于“发请求request”,返回的数据data是FutureData的实例,就相当于提货单,而不是真正的“蛋糕”。在过一段时间后(sleep一段时间后),调用data1.getContent(),也就是拿提货单获取执行结果。

下面来看一下,顾客定蛋糕后,蛋糕店做了什么:

  1. public class Host   
  2.    // public Data request(final int count, final char c) 
  3.   //原来的代码会报错,取不到getContent() ,改为如下代码
  4.      public FutureData request(final int count, final char c) {     
  5.         System.out.println("request(" count ", " ") BEGIN");   
  6.   
  7.         // (1) 建立FutureData的实体   
  8.         final FutureData future new FutureData();   
  9.   
  10.         // (2) 为了建立RealData的实体,启动新的线程   
  11.         new Thread()                                         
  12.             public void run()   
  13.              //在匿名内部类中使用count、future、c。                        
  14.                 RealData realdata new RealData(count, c);   
  15.                 future.setRealData(realdata);   
  16.                                                              
  17.         }.start();                                             
  18.   
  19.         System.out.println("request(" count ", " ") END");   
  20.   
  21.         // (3) 取回FutureData实体,作为传回值   
  22.         return future;   
  23.     }   
  24.  
   host("蛋糕店")在接到请求后,先生成了“提货单”FutureData的实例future,然后命令“蛋糕师傅”RealData去做蛋糕,realdata相当于起个线程去做蛋糕了。然后 host返回给顾客的仅仅是“提货单”future,而不是蛋糕。当蛋糕做好后, 蛋糕师傅才能给对应的“提货单”蛋糕,也就是future.setRealData(realdata)。

  

下面来看看蛋糕师傅是怎么做蛋糕的:

建立一个字符串,包含count个c字符,为了表现出犯法需要花费一些时间,使用了sleep。

 public class RealData implements Data {   
  1.     private final String content;   
  2.     public RealData(int count, char c) {   
  3.         System.out.println("making RealData(" count ", " ") BEGIN");   
  4.         char[] buffer new char[count];   
  5.         for (int 0count; i++) {   
  6.             buffer[i] c;   
  7.             try {   
  8.                 Thread.sleep(1000);   
  9.             catch (InterruptedException e) {   
  10.             }   
  11.         }   
  12.         System.out.println("making RealData(" count ", " ") END");   
  13.         this.content new String(buffer);   
  14.     }   
  15.     public String getContent() {   
  16.         return content;   
  17.     }   
  18.  

     现在来看看“提货单”future是怎么与蛋糕"content"对应的:

 
public class FutureData implements Data {   
  1.     private RealData realdata null;   
  2.     private boolean ready false;   
  3.   
  4.     public synchronized void setRealData(RealData realdata) {   
  5.         if (ready)                           
  6.             return    // 防止setRealData被调用两次以上。 
  7.         }   
  8.         this.realdata realdata;   
  9.         this.ready true;   
  10.         notifyAll();   
  11.     }   
  12.     public synchronized String getContent() {   
  13.         while (!ready) {   
  14.             try {   
  15.                 wait();   
  16.             catch (InterruptedException e) {   
  17.             }   
  18.         }   
  19.         return realdata.getContent();   
  20.     }   
  21.  

   顾客做完自己的事情后,会拿着自己的“提货单”来取蛋糕:

  

System.out.println("data1 " data1.getContent());  

 

 这时候如果蛋糕没做好,就只好等了:

 
while (!ready) {   
  1.             try {   
  2.                 wait();   
  3.             catch (InterruptedException e) {   
  4.             }   
  5. //等做好后才能取到     
  6. return realdata.getContent();  

    程序分析

 

    对于每个请求,host都会生成一个线程,这个线程负责生成顾客需要的“蛋糕”。在等待一段时间以后,如果蛋糕还没有做好,顾客还必须等待。直到“蛋糕被做好”,也就是

future.setRealData(realdata); 执行以后,顾客才能拿走蛋糕。

   每个线程只是专门负责制作特定顾客所需要的“蛋糕”。也就是顾客A对应着蛋糕师傅A,顾客B对应着蛋糕师傅B。即使顾客B的蛋糕被先做好了,顾客A也只能等待蛋糕师傅A把蛋糕做好。换句话说,顾客之间没有竞争关系。

   类FutureData的两个方法被设置为synchronized,实际上蛋糕师傅A与顾客A之间的互斥关系,也就是顾客A必须等待蛋糕师傅A把蛋糕做好后,才能拿走,而与蛋糕师傅B是否做好了蛋糕没有关系。

参考结果:

main BEGIN
request(10, A) BEGIN
request(10, A) END
request(20, B) BEGIN
request(20, B) END
request(30, C) BEGIN
request(30, C) END
main otherJob BEGIN
making RealData(10, A) BEGIN
making RealData(20, B) BEGIN
making RealData(30, C) BEGIN
main otherJob END
making RealData(10, A) END
data1 = AAAAAAAAAA
making RealData(20, B) END
data2 = BBBBBBBBBBBBBBBBBBBB
making RealData(30, C) END
data3 = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
main END


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值