在Java平臺,實現異步調用的角色有如下三個角色:調用者、 提貨單 、真實數據,一個調用者在調用耗時操作,不能立即返回數據時,先返回一個提貨單
.然后在過一斷時間后憑提貨單來獲取真正的數據.去蛋糕店買蛋糕,不需要等蛋糕做出來(假設現做要很長時間),只需要領個提貨單就可以了(去干別的
事情),等到蛋糕做好了,再拿提貨單取蛋糕就可以了。
- package?com.somnus.async;??
- ??
- /**?
- ?*??
- ?*?@Description:?顧客?
- ?*?@author?Somnus?
- ?*?@date?2016年3月9日?下午7:20:41?
- ?*?@version?1.0?
- ?*/??
- public?class?Customer?{??
- ??
- ????public?static?void?main(String[]?args)?{??
- ????????System.out.println("main?BEGIN");??
- ????????CakeShop?host?=?new?CakeShop();??
- ????????Cake?cake1?=?host.request(10,?'A');??
- ????????Cake?cake2?=?host.request(20,?'B');??
- ????????Cake?cake3?=?host.request(30,?'C');??
- ????????System.out.println("main?otherJob?BEGIN");??
- ????????try?{??
- ????????????Thread.sleep(2000);??
- ????????}?catch?(InterruptedException?e)?{??
- ????????}??
- ??
- ????????System.out.println("main?otherJob?END");??
- ????????System.out.println("cake1?=?"?+?cake1.getCake());??
- ????????System.out.println("cake2?=?"?+?cake2.getCake());??
- ????????System.out.println("cake3?=?"?+?cake3.getCake());??
- ????????System.out.println("main?END");??
- ??
- ????}??
- }??
?
這里的Customer類就相當于“顧客”,CakeShop就相當于“蛋糕店”,顧客向“蛋糕店”定蛋糕就相當于“發請求request”,返回的數據cake是
DeliveryOrder的實例,就相當于提貨單,而不是真正的“蛋糕”。在過一段時間后(sleep一段時間后),調用data1.getContent(),也就是拿提貨單獲取
執行結果。
?
下面來看一下,顧客定蛋糕后,蛋糕店做了什么:
?
- package?com.somnus.async;??
- ??
- /**?
- ?*?@Description:?TODO?
- ?*?@author?Somnus?
- ?*?@date?2016年3月9日?下午7:21:32?
- ?*?@version?1.0?
- ?*/??
- public?class?CakeShop?{??
- ??
- ????public?Data?request(final?int?count,?final?char?c)?{??
- ??
- ????????System.out.println("request("?+?count?+?",?"?+?c?+?")?BEGIN");??
- ????????//?(1)?建立DeliveryOrder的實體??
- ????????final?DeliveryOrder?order?=?new?DeliveryOrder();??
- ??????????
- ????????//?(2)?為了建立RealData的實體,啟動新的線程??
- ????????new?Thread()?{??
- ????????????public?void?run()?{??
- ????????????????//在匿名內部類中使用count、order、c。??
- ????????????????CakeBaker?cakeBaker?=?new?CakeBaker(count,?c);??
- ????????????????order.setCakeBaker(cakeBaker);??
- ????????????}??
- ????????}.start();??
- ????????System.out.println("request("?+?count?+?",?"?+?c?+?")?END");??
- ??????????
- ????????//?(3)?取回FutureData實體,作為傳回值??
- ????????return?order;??
- ??
- ????}??
- }??
?
CakeShop("蛋糕店")在接到請求后,先生成了“提貨單”DeliveryOrder的實例order,然后命令“蛋糕師傅CakeBaker去做蛋糕,CakeBaker相當于起
個線程去做蛋糕了。然后host返回給顧客的僅僅是“提貨單”future,而不是蛋糕。當蛋糕做好后,蛋糕師傅才能給對應的“提貨單”蛋糕,也就
是order.setCakeBaker(cakeBaker);。
下面來看看蛋糕師傅是怎么做蛋糕的:
建立一個字符串,包含count個c字符,為了表現出犯法需要花費一些時間,使用了sleep。
?
- package?com.somnus.async;??
- ??
- /**?
- ?*?@Description:?蛋糕師傅?
- ?*?@author?Somnus?
- ?*?@date?2016年3月9日?下午7:22:52?
- ?*?@version?1.0?
- ?*/??
- public?class?CakeBaker?implements?Cake?{??
- ????private?final?String?cake;??
- ??
- ????public?CakeBaker(int?count,?char?c)?{??
- ????????System.out.println("making?cake("?+?count?+?",?"?+?c?+?")?BEGIN");??
- ????????char[]?buffer?=?new?char[count];??
- ????????for?(int?i?=?0;?i?<?count;?i++)?{??
- ????????????buffer[i]?=?c;??
- ????????????try?{??
- ????????????????Thread.sleep(3000);??
- ????????????}?catch?(InterruptedException?e)?{??
- ????????????????e.printStackTrace();??
- ????????????}??
- ????????}??
- ????????System.out.println("making?cake("?+?count?+?",?"?+?c?+?")?END");??
- ????????this.cake?=?new?String(buffer);??
- ????}??
- ??
- ????public?String?getCake()?{??
- ????????return?cake;??
- ????}??
- ??
- }??
?
現在來看看“提貨單”order是怎么與蛋糕"cake"對應的:
- package?com.somnus.async;??
- ??
- /**?
- ?*?@Description:?提貨單?
- ?*?@author?Somnus?
- ?*?@date?2016年3月9日?下午7:25:06?
- ?*?@version?1.0?
- ?*/??
- public?class?DeliveryOrder?implements?Cake?{??
- ????private?CakeBaker?cakeBaker?=?null;??
- ??
- ????private?boolean?ready?=?false;??
- ??
- ????public?synchronized?void?setCakeBaker(CakeBaker?cakeBaker)?{??
- ????????if?(ready)?{??
- ????????????return;?//?防止setCakeBaker被調用兩次以上。??
- ????????}??
- ????????this.cakeBaker?=?cakeBaker;??
- ????????this.ready?=?true;??
- ????????notifyAll();??
- ????}??
- ??
- ????public?synchronized?String?getCake()?{??
- ????????while?(!ready)?{??
- ????????????try?{??
- ????????????????wait();??
- ????????????}?catch?(InterruptedException?e)?{??
- ????????????????e.printStackTrace();??
- ????????????}??
- ????????}??
- ????????return?cakeBaker.getCake();??
- ????}??
- ??
- }??
顧客做完自己的事情后,會拿著自己的“提貨單”來取蛋糕:
- System.out.println("cake1?=?"?+?cake1.getCake());??
這時候如果蛋糕沒做好,就只好等了:
- while?(!ready)?{??
- ????try?{??
- ????????wait();??
- ????}?catch?(InterruptedException?e)?{??
- ????????e.printStackTrace();??
- ????}??
- }??
//等做好后才能取到
- return?cakeBaker.getCake();??
程序分析
對于每個請求,host都會生成一個線程,這個線程負責生成顧客需要的“蛋糕”。在等待一段時間以后,如果蛋糕還沒有做好,顧客還必須等待。
直到“蛋糕被做好”,也就是
order.setCakeBaker(cakeBaker);執行以后,顧客才能拿走蛋糕。
每個線程只是專門負責制作特定顧客所需要的“蛋糕”。也就是顧客A對應著蛋糕師傅A,顧客B對應著蛋糕師傅B。即使顧客B的蛋糕被先做好了,
顧客A也只能等待蛋糕師傅A把蛋糕做好。換句話說,顧客之間沒有競爭關系。
?
類DeliveryOrder的兩個方法被設置為synchronized,實際上蛋糕師傅A與顧客A之間的互斥關系,也就是顧客A必須等待蛋糕師傅A把蛋糕做好后,
才能拿走,而與蛋糕師傅B是否做好了蛋糕沒有關系。