tbwshc

          #

          經驗分享:我的JavaEE學習道路

           從很小都認識蘋果機了,我不記得我是否在小學的時候學過Basic,只記得大學實驗室里的蘋果機我的確是摸過(得益于我是教師子弟,有“特殊待遇”),也看到計算機系的學生們編寫的游戲。初中,有了自己的游戲機。玩過魂斗羅,坦克。當時覺得很不過癮,心想以后能自己編寫游戲就好了,于是立志以后做個程序員。

              高考不順利,只考上了普通學校電力專業。這還是幸虧當時學校的羅老師(那四年,她一直都在幫助我)看到我以前的成績還不錯,決定要下我,否則,我就往下落的更厲害了。電力專業幾乎沒有計算機課程。等到學校關于自動化的時候,開始接觸了匯編,和自學了C.當時很羨慕學計算機的那個女老鄉,姓楊,呵呵,因為羨慕,還被別人誤認為我喜歡她,其實完全不是,她根本對計算機沒有興趣,畢業后也去了當公務員,可惜啊,早知道如此,她何必要高出幾分,占據我喜歡的專業呢,我甚至為此感到暗自不爽。 不過大學還是學到了一些計算機皮毛知識,C程序寫的很好,記得寫了一個模仿TT的打字程序。匯編也不錯,寫個文件病毒,源代碼10K,編譯鏈接后3K多,很大,AV95能識別出來,我想大概是我寫的太爛,別的殺毒程序,象KV300,都不認為這是個病毒。不管怎么樣,我沒有拿這個干啥壞事情。這始終是不光彩的事情。

              該畢業了,家鄉的供電局沒能進去。我怨我老媽沒有幫我跑關系,其實我跟我老媽都不愿意我去,我老媽是不想讓我回銅仁,我自己也不想做電力職工(雖然在我們那是一等的暴有錢的工作),我還是喜歡去做個程序員,為此也退掉了別的電力相關的工作。但是,我始終不到該如何入門。畢業了,門衛老頭開始趕我們出去,我工作無著落,同學們都已經回到家鄉開始上班了,我還在跟老頭打游擊。他進我退,他退我上床休息,有次晚上洗澡,被他發現,嚇得我光著屁股從三樓跑到5樓,再跑回三樓。呵呵,那時候整個宿舍樓都空了,所以也不算丟臉了。

              好運終于堅持到了,網上碰到一網友,后來我叫他秦哥,他說他需要一個人幫他做個網站。我便毛遂自薦了一下,其實,那時候我不懂做網站,不懂ASP,不過我相信我的能力,果然,一段適應時間后,我成了他得力的幫手,我也開始正式進入程序員這個行業了。相比現在的很多學生,我覺得他們比我幸運多了,在大學的時候都已經學習到很多知識,甚至是已經有一定的實踐了。剛畢業就能踏入這行,還能有地方住,要知道我不光要跟老頭打游擊,有時候還睡在電腦城廣場的板凳上,早上起來看的第一眼便是保安和他身邊對我俯視眈眈的狼狗。

              搞懂了ASP和網站后,開始考慮學更多的東西,這時候我已經放棄了我編寫游戲程序的夢想了,因為我跟本不知道如何去追逐這個夢想。我也放棄了我比較擅長的單片機開發(現在應該叫嵌入式)。我轉向了Java.俗話說,女怕嫁錯狼,男怕入錯行。8年前的這個時候,我算是馬馬虎虎開始我的JavaEE道路吧,這兒有點體會就是一定要堅持自己的理想,而這個理想,應該能養活你的,能讓你有興趣做的事情。

              初學Java,有些迷惑,當時微軟有個VJ++,我先買了一本介紹這樣的書看,結構后來發現它主要是桌面程序的,而且,跟我知道的JSP不太一樣。當時也沒有想到可以找人問或者論壇上發給帖子問。幸好后來明智的轉到了JSP,挺簡單,跟ASP差不多,tb概念都能通用(畢竟處理的問題都一樣嘛),比起現在的孩子來說,我當時學的東西太少了,不用學習hibernate,spring,j2ee,也不用學習ant,Junit什么的,呵呵,關鍵還是當時書太少,見識少,也沒有這么多新玩意。好處就是我能深入JSP技術,為以后理解這些Web框架打下了很好的基礎。不象現在的孩子,還搞不懂JSP,就去弄MVC,搞的本末倒置了。

              J2EE技術得到提高得益于后來到了北京,去了ZZ公司,現在看來,好不夸張的說,從這個公司出來的程序員,都有一定創新能力和解決問題能力。一到這公司,就做了一個算是大的項目,幾十個人,還包括國防科技大學的數十個博士,當時用到了很多J2EE技術,象EJB,JMS都用到了,當時不懂這些,費了很多力氣去學,還好項目本身就是個很好的學習材料。通過專研項目代碼學到了不少東西,遠比看書強多了?,F在的很多培訓方式都是通過做獨立完成項目來學習技術,這是很有道理的。當時那個項目做了一年,期間我對自己要求蠻高的,總會多學點東西,比如學了EJB 無狀態會話Bean,雖然項目沒有用到有狀態Bean,但還是花時間去搞明白。這個項目期間,頭一次知道了還有英文資料這么一說,象什么Weblogic使用說明,Java文檔都,我都會強迫自己去看,有時候打印下來,躺在小床,打開臺燈看,那感覺真是美阿。

          posted @ 2012-08-02 16:56 chen11-1| 編輯 收藏

          J2ME編程程序開發平臺的概念

          對于J2ME編程開發平臺,在其他平臺風生水起的時候,J2ME編程開發平臺似乎很沉寂。本文將簡單介紹一下幾個J2ME編程開發平臺的重要概念。

            內存

            我們一直在強調,移動信息設備的內存非常小,使用起來應該加倍的珍惜,但是我們卻很少知道這些內存是如何分類的,下面將做詳細的介紹。事實上MIDP設備的內存分為三種,

            1.ProgrammeMemory、Heap、persistentStorage

            ProgrammeMemory是移動信息設備分配給MIDletsuite的空間,因為MIDletsuite是以jar文件進行發布的,所以這個文件的大小可以認為是ProgrammeMemory的大小。一些廠商對ProgrammeMemory的最大值是有限制的,例如我的Nokia6108的最大值是64k,超過的話將不能進行安裝。減小MIDletsuite的大小非常重要,一個便捷的方法就是使用混淆器對應用程序進行混淆,這樣可以減小jar文件的大小。在以后的文章中我會談到如何使用Proguard.

            Heap是應用程序在運行過程中存放所創建的對象的存儲空間,tb本地變量和成員變量也是放在Heap上的,MIDP設備中提供的Heap空間大概在幾十k到幾百K.

            PersistentStorage的空間是用來實現MIDP應用程序的本地數據持久性存儲的,在RecordManagementSystem從入門到精通中我做了詳細的介紹這里就不再多說了。

            2.ConnectedLimitedDeviceConfiguration

            CLDC包括一個Java虛擬機和一系列的基礎類,J2ME的專家組經過對移動信息設備進行硬件抽象后得到他們的特點,然后設計并實現了在移動信息設備上運行的java虛擬機,通常我們把它叫做KVM.在CLDC1.0還同時提供了由java.io、java.lang、javax.microediton.io、java.util組成的基礎類。在CLDC1.1里面添加了java.lang.ref.

            3.MobileInfomationDeviceProfile

            MIDP是運行在CLDC基礎之上的,在MIDP中定義了應用程序的生命周期、用戶圖形界面、數據管理系統等子集,從而構建起了J2ME平臺。通常,J2ME平臺由一個CLDC和一個或者多個Profile構成。

          posted @ 2012-08-01 16:40 chen11-1 閱讀(664) | 評論 (0)編輯 收藏

          jQuery繪圖插件jCanvas 繪制窗口的技巧分享

           Jquery是繼prototype之后又一個優秀的Javascrīpt框架。它是輕量級的js庫,除了兼容CSS3外,還兼容各種瀏覽器+)。jQuery使用戶能更方便地處理HTML documents、events、實現動畫效果,并且方便地為網站提供AJAX交互。

            HTML5 中新定義的 HTML 元素,可以用來在 HTML 頁面中通過 JavaScriptb 繪制圖形、制作動畫?,F在要推薦的 jCanvas 就是一個 jQuery 的繪圖插件,它封裝了一些繪制圖形的方法,只需編寫幾行代碼即可生成圖形。

            以下是JCanvas 繪制窗口并對其監聽的程序代碼分享

            import java.awt.*;

            import javax.swing.*;

            import java.awt.event.*;

            class JCanvas extends JComponent

            {

            public JCanvas()

            {

            setDoubleBuffered(true);

            }

            public void paintComponent(Graphics g)

            {

            Dimension size = getSize();

            g.setColor(getBackground());

            g.fillRect(0,0,size.width,size.height);

            }

            }

            class TestJCanvas

            {

            public static void main(String s[] )

            {

            MyWindowListener l = new MyWindowListener();

            JCanvas c = new JCanvas();

            c.setBackground(Color.yellow);

            JFrame f = new JFrame("Test JCanvas...");

            f.addWindowListener(l);

            f.getContentPane().add(c,BorderLayout.CENTER);

            f.pack();

            f.setSize(500,400);

            f.show();

            }

            }

            class MyWindowListener extends WindowAdapter

            {

            public void windowClosing(WindowEvent e)

            {

            System.exit(0);

            }

            }

          posted @ 2012-08-01 16:37 chen11-1 閱讀(1854) | 評論 (2)編輯 收藏

          JavaScript框架:jQuery選擇器精通教程

          雖然jQuery上手簡單,相比于其他庫學習起來較為簡單,但是要全面掌握,卻不輕松。因為它涉及到網頁開發的方方面面,提供的方法和內部變化有上千種之多。初學者常常感到,入門很方便,提高很困難。本文的目標是將jQuery選擇器做一個系統的梳理,試圖理清jQuery的設計思想,找出學習的脈絡,使讀者從入門到精通。

            jQuery是什么

            簡單的說,jQuery是一個JavaScript框架,它的宗旨是:寫更少的代碼,做更多的事情。對于Web開發人員而言,jQuery是一個功能強大的JavaScript庫,能更加快速開發相關應用,例如AJAX交互,JavaScript動畫效果等。對于Web設計師而言,jQuery封裝了Javascript源碼細節,實現了與HTML標簽的有效分離,便于設計師更加專注于Web頁面設計效果。基于此,網頁的用戶體驗大大增強,包括網頁的交互性,視覺效果等等。

            jQuery的核心設計思想是:選擇某個網頁元素,然后對其進行某種操作。那么如何選擇、定位某個網頁元素呢?對于JavaScript開發人員而言,通常的一種手段是document.getElementById()。而在jQuery語法中,使用的是美元符號“$”,等價的選擇表達式寫法為:

          var someElement = $("#myId");

            jQuery之所以稱之為“jQuery”,主要就是因為它強大的選擇器,也就是Javascript Query的意思。下面,我們具體介紹jQuery選擇器相關的設計思想:

            一、jQuery基本選擇器

            前面提到,選擇器是jQuery的特色。jQuery的基本選擇器主要分為tb以下五種類型:

            1. $(“#myId”) // 選擇ID為myId的網頁元素

            2. $(“標簽名”) // 例如$(“div”)獲取的就是HTML文檔中的所有的div元素的jQuery對象集合

            3. $(“.myClass”) // 獲取的是HTML文檔中所有的class為“myClass”的元素集合

            4. $(“*”) // 這個獲取的是HTML文檔中的所有的元素

            5. $(“selector1,selector2,selector3…selectorN “) // 這種選擇器叫做組選擇器。例如:$(“span,#two”)

            // 選取所有的span標簽元素和id=two的元素。

            二、jQuery層次選擇器

            無論何時,通過jQuery選擇器獲取的jQuery對象任何時候都是一組元素。jQuery的層次選擇器主要分為以下兩種類型:

            1. $(“ancestor descendant”):選取parent元素后所有的child元素。ancestor的中文意思是“祖先”,descendant的中文意思是“后代”。例如:

            $(“body div”) 選取body元素下所有的div元素。

            $(“div#test div”) 選取id為“test”的div所包含的所有的div子元素

            2. $(“parent > child”):選取parent元素后所有的第一個child元素。例如:

            $(“body > div”) 選取body元素下所有的第一級div元素。

            $(“div#test > div”) 選取id為“test”的div所包含的所有的第一級div子元素
           三、jQuery過濾選擇器

            jQuery最基本過濾選擇器包括:

            1. :first // 選取第一個元素。$(“div:first”)選取所有div元素中的第一個div元素

            2. :last // 選取最后一個元素。$(“div:last”)選取所有div元素中的最后一個div元素

            3. :even // 選取索引是偶數的所有元素。$(“input:even”)選取索引是偶數的input元素。

            4. :odd // 選取索引是奇數的所有元素。$(“input:odd”)選取索引是奇數的input元素。

            5. :eq(index) // 選取索引等于index的元素。$(“input:eq(1)”)選取索引等于1的input元素。

            6. :gt(index) // 選取索引大于index的元素。$(“input:gt(1)”)選取索引大于1的input元素。

            7. :lt(index) // 選取索引小于index的元素。$(“input:lt(3)”)選取索引小于3的input元素。

            jQuery內容過濾選擇器,可以輕松地對DOM文檔中的文本內容進行篩選,從而準確地選取我們所需要的元素。

            1. :contains(text) // 選取含有文本內容為“text”元素。$(“div:contains(‘你’)”)選取含有文本“你”的div元素。

            2. :empty // 選取不包含子元素和文本的空元素。$(“div:empty”)選取不包含子元素(包括文本元素)的div空元素。

            3. :parent // 選取含有子元素或者文本的元素。$(“div:parent”)選取擁有子元素(包括文本元素)的div元素。

            可以看見,jQuery內容過濾選擇器的過濾規則主要體現在它所包含的子元素或文本內容上。

            jQuery可見性過濾選擇器的用法如下:

            1. :hidden // 選取所有不可見的元素。$(“:hidden”)選取網頁中所有不可見的元素。

            2. :visible // 選取所有可見元素。$(“div:visible”)選取所有可見的div元素。

            jQuery屬性過濾選擇器的過濾規則是通過元素的屬性來獲取相應的元素。

            1. [attribute] // 選擇擁有此屬性的元素。$(“div[id]“)選取擁有屬性id的元素。

            2. [attribute=value] // 選取屬性值為value的元素。$(“div[name=test]“)選取屬性name的值為“test”的div元素。

            3. [attribute!value] // 選取屬性值不等于value的元素。

            4.[attribute^=value] // 選取屬性的值以value開始的元素。

            5. [attribute$=value] // 選取屬性的值以value為結束的元素。

            6. [attribute*=value] // 選取屬性的值含有value的元素。

            7. [selector1] [selector2] [selectorN] //復合屬性選擇器。$(“div[id][name*=test]“)選取擁有屬性id,且屬性name的值含有“test”的div元素

            jQuery子元素過濾選擇器的過濾規則相對于其它的選擇器稍微有些復雜。

            1. :nth-child(index/even/odd/equation) // 選取每個父元素下的第index個子元素或者奇偶元素。

            2. :first-child // 選取每個父元素的第一個子元素

            3. :last-child // 選取每個父元素的最后一個子元素

            jQuery表單對象屬性過濾選擇器主要是對所選擇的表單元素進行過濾,例如選擇不可用的表單元素、被選中的下拉框、多選框等等。

            1. :enabled // 選取所有可用的表單元素。$(“#form1 :enabled”)選取id為“form1”的表單內的所有可用元素。

            2. :disabled // 選取所有不可用的表單元素。

            3. :checked // 選取所有被選中的元素。$(“input:checked”)選取所有被選中的元素。

            4. :selected // 選取所有被選中的選項元素。$(“select :selected”)選取所有被選中的選項元素(option)。

            jQuery中引入了表單選擇器,讓我們能極其方便地獲取到一個表單中的某個或某類型的元素。

           

          posted @ 2012-08-01 16:36 chen11-1 閱讀(906) | 評論 (0)編輯 收藏

          Java 異步消息處理

          在前一節實現異步調用的基礎上 , 現在我們來看一下一個完善的 Java 異步消息處理機制 .

          [ 寫在本節之前 ]

                 在所有這些地方 , 我始終沒有提到設計模式這個詞 , 而事實上 , 多線程編程幾乎每一步都在應該設計模式 . 你只要能恰如其份地應用它 , 為什么要在意你用了某某名稱的模式呢 ?

                 一個說書人它可以把武功招數說得天花亂墜 , 引得一班聽書客掌聲如雷 , 但他只是說書的 . 真正的武林高手也許并不知道自己的招式在說書人口中叫什么 , 這不重要 , 重要的是他能在最恰當的時機把他不知名的招式發揮到極致 !

                 你了解再多的設計模式 , 或你寫出了此類的著作 , 并不重要 , 重要的是你能應用它設計出性能卓越的系統 .

           

           

                 本節的這個例子 , 如果你真正的理解了 , 不要懷疑自己 , 你已經是 Java 高手的行列了 . 如果你拋開本節的內容 , 五天后能自己獨立地把它再實現一次 , 那你完全可以不用再看我寫的文章系列了 , 至少是目前 , 我再也沒有更高級的內容要介紹了 .

                 上節的 Java 異步調用為了簡化調用關系 , 很多角色被合并到一個類中實現 , 為了幫助大家改快地抓住核心的流程 . 那么一個真正的異步消息處理器 , 當然不是這樣的簡單 .

          一.    它要能適應不同類型的請求 :

          本節用 makeString 來說明要求有返回值的請求 . 用 displayString 來說明不需要返回值的請求 .

          二.    要能同時并發處理多個請求 , 并能按一定機制調度 :

          本節將用一個隊列來存放請求 , 所以只能按 FIFO 機制調度 , 你可以改用 LinkedList, 就可以簡單實現一個優先級 ( 優先級高的 addFirst, 低的 addLast).

          三.    有能力將調用的邊界從線程擴展到機器間 (RMI)

          四.    分離過度耦合 , 如分離調用句柄 ( 取貨憑證 ) 和真實數據的實現 . 分離調用和執行的過程 , 可以盡快地將調返回 .

           

          現在看具體的實現 :

          public interface Axman {

            Result resultTest(int count,char c);

            void noResultTest(String str);

          }

          這個接口有兩個方法要實現 , 就是有返回值的調用 resultTest 和不需要返回值的調用

          noResultTest, 我們把這個接口用一個代理類來實現 , 目的是將方法調用轉化為對象 , 這樣就可以將多個請求 ( 多個方法調 ) 放到一個容器中緩存起來 , 然后統一處理 , 因為 Java 不支持方法指針 , 所以把方法調用轉換為對象 , 然后在這個對象上統一執行它們的方法 , 不僅可以做到異步處理 , 而且可以將代表方法調用的請求對象序列化后通過網絡傳遞到另一個機器上執行 (RMI). 這也是 Java 回調機制最有力的實現 .

                 一個簡單的例子 .

                 如果 1: 做 A

                 如果 2: 做 B

          如果 3: 做 C

          如果有 1000 個情況 , 你不至于用 1000 個 case 吧 ? 以后再增加呢 ?

          所以如果 C/C++ 程序員 , 會這樣實現 : (c 和 c++ 定義結構不同 )

           

          type define struct MyStruct{

          int mark;

          (*fn) ();

          } MyList;

                

                 然后你可以聲明這個結構數據 :

                 {1,A,

                   2,B

                   3,C

          }

          做一個循環 :

          for(i=0;i<length;i++) {

                 if( 數據組 [i].mark == 傳入的值 ) ( 數據組 [i].*fn)();

          }

          簡單說 c/c++ 中將要被調用的涵數可以被保存起來 , 然后去訪問 , 調用 , 而 Java 中 , 我們無法將一個方法保存 , 除了直接調用 , 所以將要調用的方法用子類來實現 , 然后把這些子類實例保存起來 , 然后在這些子類的實現上調用方法 :

          interface My{

                 void test();

          }

           

          class A implements My{

                 public void test(){

                        System.out.println(“A”):

          }

          }

          class B implements My{

                 public void test(){

                        System.out.println(“B”):

          }

          }

           

          class C implements My{

                 public void test(){

                        System.out.println(“C”):

          }

          }

           

          class MyStruct {

                

                 int mark;

                 My m;

                 public MyStruct(int mark,My m){this.mark = amrk;this.m = m}

          }

          數組 :

          { new MyStruct(1,new A()),new MyStruct(2,new B()),new MyStruct(3,new C())}

          for(xxxxxxxxx) if( 參數 == 數組 [i].mark) 數組 [i].m.test();

           

          這樣把要調用的方法轉換為對象的保程不僅僅是可以對要調用的方法進行調度 , 而且可以把對象序列化后在另一臺機器上執行 , 這樣就把調用邊界從線程擴展到了機器 .

           

          回到我們的例子 :

          class Proxy implements Axman{

            private final Scheduler scheduler;

            private final Servant servant;

           

            public Proxy(Scheduler scheduler,Servant servant){

              this.scheduler = scheduler;

              this.servant = servant;

            }

            public Result resultTest(int count,char c){

              FutureResult futrue = new FutureResult();

              this.scheduler.invoke(new ResultRequest(servant,futrue,count,c));

              return futrue;

            }

           

            public void noResultTest(String str){

              this.scheduler.invoke(new NoResultRequest(this.servant,str));

            }

          }

           

          其中 scheduler 是管理對調用的調度 , servant 是真正的對方法的執行 :

           

          Servant 就是去真實地實現方法 :

           

          class Servant implements Axman{

            public Result resultTest(int count,char c){

              char[] buf = new char[count];

              for(int i = 0;i < count;i++){

                buf[i] = c;

                try{

                  Thread.sleep(100);

                }catch(Throwable t){}

              }

              return new RealResult(new String(buf));

            }

           

            public void noResultTest(String str){

              try{

                System.out.println("displayString :" + str);

                Thread.sleep(10);

              }catch(Throwable t){}

            }

          }

          在 scheduler 將方法的調用 (invkoe) 和執行 (execute) 進行了分離 , 調用就是開始 ” 注冊 ” 方法到要執行的容器中 , 這樣就可以立即返回出來 . 真正執行多久就是 execute 的事了 , 就象一個人點燃爆竹的引信就跑了 , 至于那個爆竹什么時候爆炸就不是他能控制的了 .

          public class Scheduler extends Thread {

            private final ActivationQueue queue;

            public Scheduler(ActivationQueue queue){

              this.queue = queue;

            }

           

            public void invoke(MethodRequest request){

              this.queue.putRequest(request);

            }

           

            public void run(){

              while(true){

           

                // 如果隊列中有請求線程 , 測開始執行請求

                MethodRequest request = this.queue.takeRequest();

                request.execute();

              }

            }

          }

          在 schetbduler 中只用一個隊列來保存代表方法和請求對象 , 實行簡單的 FIFO 調用 , 你要實更復雜的調度就要在這里重新實現 :

          class ActivationQueue{

            private static final int MAX_METHOD_REQUEST = 100;

            private final MethodRequest[] requestQueue;

            private int tail;

            private int head;

            private int count;

           

            public ActivationQueue(){

              this.requestQueue = new MethodRequest[MAX_METHOD_REQUEST];

              this.head = this.count = this.tail = 0;

            }

           

            public synchronized void putRequest(MethodRequest request){

              while(this.count >= this.requestQueue.length){

                try {

                  this.wait();

                }

                catch (Throwable t) {}

              }

              this.requestQueue[this.tail] = request;

              tail = (tail + 1)%this.requestQueue.length;

              count ++ ;

              this.notifyAll();

           

            }

           

           

            public synchronized MethodRequest takeRequest(){

              while(this.count <= 0){

                try {

                  this.wait();

                }

                catch (Throwable t) {}

           

              }

           

              MethodRequest request = this.requestQueue[this.head];

              this.head = (this.head + 1) % this.requestQueue.length;

              count --;

              this.notifyAll();

              return request;

            }

          }

           

          為了將方法調用轉化為對象 , 我們通過實現 MethodRequestb 對象的 execute 方法來方法具體方法轉換成具體對象 :

          abstract class MethodRequest{

            protected final Servant servant;

          }

          posted @ 2012-07-31 15:38 chen11-1 閱讀(2578) | 評論 (0)編輯 收藏

          Java模擬異步消息的發送與回調

          本文的目的并不是介紹使用的什么技術,而是重點闡述其實現原理。

           

          一、 異步和同步

          講通俗點,異步就是不需要等當前執行的動作完成,就可以繼續執行后面的動作。

           

          通常一個程序執行的順序是:從上到下,依次執行。后面的動作必須等前面動作執行完成以后方可執行。這就是和異步相對的一個概念——同步。

           

          案例:

          A、張三打電話給李四,讓李四幫忙寫份材料。

          B、李四接到電話的時候,手上有自己的工作要處理,但他答應張三,忙完手上的工作后馬上幫張三寫好材料,并傳真給張三。

          C、通完電話后,張三外出辦事。

           

          說明:

          張三給李四通完電話后,就出去辦事了,他并不需要等李四把材料寫好才外出。那么張三讓李四寫材料的消息就屬于異步消息。

          相反,如果張三必須等李四把材料寫好才能外出辦事的話,那么這個消息就屬于同步消息了。

           

          二、 異步的實現

          傳統的程序執行代碼都是從上到下,一條一條執行的。

          但生活中有很多情況并不是這樣,以上的案例中,如果李四需要幾個小時以后才能幫張三寫好材料的話,那張三就必須等幾個小時,這樣張三可能會崩潰或者抓狂。

           

          這種一條龍似的處理,顯示不太合理。

           

          可以使用以下辦法來處理這種問題:

          張三找王五去給李四打電話,等李四寫好材料后,由王五轉交給張三。這樣張三就可以外出辦其他的事情了。

           

          問題得到了合理的解決,之前張三一條線的工作,由張三和王五兩條線來完成了,兩邊同時進行,彼此不耽誤。

           

          三、 計算機語言的實現

          辦法有了,如何用程序來模擬實現呢?

           

          A、以前由一個線程來處理的工作,可以通過新增一個線程來達到異步的目的。這也就是JAVA中的多線程技術。

          B、最后李四寫好的材料必須交給張三,以做他用。這就是回調。

           

          回調你可以這樣來理解:

          A發送消息給B,B處理好A要求的事情后,將結果返回給A,A再對B返回的結果來做進一步的處理。

           

          四、 Java代碼的實現

          A、 回調的實現

           


          Java代碼tb 
            
          public interface CallBack {   
                
              public void execute(Object... objects );   
           
          public interface CallBack { public void execute(Object... objects ); }

           

          Java是面向對象的語言,因此回調函數就變成了回調接口。

           

          B、 消息的發送者

           


          Javatb代碼
            
          public class Local implements CallBack,Runnable{   
                 
                
              private Remote remote;   
                 
                
              private String message;   
                 
              public Local(Remote remote, String message) {   
                  super();   
                  this.remote remote;   
                  this.message message;   
              }   
            
                
              public void sendMessage()   
              {   
                    
                  System.out.println(Thread.currentThread().getName());   
                    
                  Thread thread new Thread(this);   
                  thread.start();   
                    
                  System.out.println("Message has been sent by Local~!");   
              }   
            
                
              public void execute(Object... objects {   
                    
                  System.out.println(objects[0]);   
                    
                  System.out.println(Thread.currentThread().getName());   
                    
                  Thread.interrupted();   
              }   
                 
              public static void main(String[] args)   
              {   
                  Local local new Local(new Remote(),"Hello");   
                     
                  local.sendMessage();   
              }   
            
              public void run() {   
                  remote.executeMessage(message, this);   
                     
                

          C、 遠程消息的接收者

           

           


          Java代碼
            
          public class Remote {   
            
                
              public void executeMessage(String msg,CallBack callBack)   
              {   
                    
                  for(int i=0;i<1000000000;i++)   
                  {   
                         
                  }   
                    
                  System.out.println(msg);   
                  System.out.println("I hava executed the message by Local");   
                    
                  callBack.execute(new String[]{"Nice to meet you~!"});   
              }   
                 
           
          public class Remote { public void executeMessage(String msg,CallBack callBack) { for(int i=0;i<1000000000;i++) { } System.out.println(msg); System.out.println("I hava executed the message by Local"); callBack.execute(new String[]{"Nice to meet you~!"}); } }

            

          執行Local類的main方法。

           

          注意Local類中紅色背景的那行:

          remote.executeMessage(message, this);

          executeMessage方法需要接收一個message參數,表示發送出去的消息,而CallBack參數是他自己,也就是這里的this。表示發送消息后,由Local類自己來處理,調用自身的execute方法來處理消息結果。

          如果這里不是用this,而是用其他的CallBack接口的實現類的話,那就不能稱之為“回調”了,在OO的世界里,那就屬于“委派”。也就是說,“回調”必須是消息的發送者來處理消息結果,否則不能稱之為回調。這個概念必須明確。

          posted @ 2012-07-31 15:35 chen11-1 閱讀(1558) | 評論 (0)編輯 收藏

          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();
           
          OK,你現在可以抽煙,喝酒,泡妞.ft會為你完成所有的工作.

          posted @ 2012-07-31 15:16 chen11-1 閱讀(22741) | 評論 (9)編輯 收藏

          用線程池啟動定時器

          (1)調用ScheduledExecutorService的schedule方法,返回的ScheduleFuture對象可以取消任務。
          (2)支持間隔重復任務的定時方式,不直接支持絕對定時方式,需要轉換成相對時間方式。

          Java代碼  
          1. Executors.newScheduledThreadPool(3).schedule(new Runnable() {          
          2.          @Override  
          3.            public void run() {   
          4.             System.out.println("響");           
          5.         }   
          6.           }, 10,TimeUnit.SECONDS);       //在10秒后響一次  
           
          Java代碼  
          1. Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable() {        //頻率   
          2.             @Override  
          3.             public void run() {   
          4.                 // TODO Auto-generated method stub   
          5.             System.out.println("響");           
          6.              }   
          7.            },    
          8.         6,   
          9.         2,   
          10.                 TimeUnit.SECONDS);       //在10秒后響之后,每隔2秒響一次  
           

          posted @ 2012-07-27 15:04 chen11-1 閱讀(1366) | 評論 (0)編輯 收藏

          xml語法 學習

          一個xml文件分為幾部分內容:
          文檔聲明
          元素
          屬性
          注釋
          CDATA區,特殊字符
          處理指令

          在編寫xml文檔,需要先使用文檔聲明,聲明xml文檔的類型。
          最簡單的聲明語法:
          <?xml version="1.0"?>
          用encoding 屬性說明文檔的字符編碼:
          <?xml version="1.0" encoding="gb2312"?>
          用standalone屬性說明文檔是否獨立:
          <?xml version="1.0" encoding="gb2312" standalone="yes"?>

          元素
          xml元素指的xml文件出現的標簽,分為開始標簽和結束標簽。
          一個xml元素可以包含字母,數字以及其他可見字符,但是遵守下面的一些規范:
          區分大小寫
          不能以數字或特殊字符開頭
          不能以xml開頭
          不能包含空格
          名稱中間不能包含冒號

          注釋
          xml文件的注釋采用 <!--注釋-->

          CDATA區別
          在編寫xml文件時,有些內容可能不想讓解析引擎解析執行,而是當作原始內容處理,把這些內容放在CDATA區。
          對于CDATA區域內的內容,tb解析程序不會處理,而是直接原封不動的輸出。
          語法:
          <![CDATA[內容]]>


          轉義字符
          對于一些單個字符,如果顯示原始樣式,可以使用轉義形式給于處理。
          特殊符號    替代符號
          &               &amp
          <                &lt
          >                &gt
          "                &quot

          處理指令
          處理指令,簡稱PI。處理指令用來指揮解析引擎如何解析xml文檔內容。
          處理指令必須要以<?作為開頭,以>作為結尾。

          posted @ 2012-07-27 15:02 chen11-1 閱讀(778) | 評論 (0)編輯 收藏

          xml約束

          xml約束
          編寫一個文檔來約束一個xml文檔的書寫規范

          常用的約束技術

          XML DTD
          XML Schema

          DTD(Document Type Definition),全程為文檔類型定義
          舉例:
          文件清單:book.xml

          Java代碼  
          1. <?xml version="1.0" encoding="UTF-8"?>   
          2. <!DOCTYPE 圖書 SYSTEM "book.dtd">          
          3. <圖書>   
          4.      <書>   
          5.             <書名>西游記</書名>   
          6.             <作者>吳承恩</作者>     
          7.             <售價>18</售價>     
          8.      </書>   
          9.      <書>   
          10.           <書名>三國演義</書名>   
          11.           <作者>羅貫中</作者>     
          12.           <售價>20</售價>   
          13.      </書>    
          14. </圖書>  

             文件清單:book.dtbd

          Java代碼  
          1. <?xml version="1.0" encoding="UTF-8"?>   
          2. <!ELEMENT 圖書 (書+)>   
          3. <!ELEMENT 書 (書名,作者,售價)>   
          4. <!ELEMENT 書名 (#PCDATA)>   
          5. <!ELEMENT 作者 (#PCDATA)>   
          6. <!ELEMENT 售價 (#PCDATA)>  

           

           

          ELEMENT 元素

          PCDATA 的意思是已經解析的字符數據,文本中的標簽會被當作標記來處理,而實體會被展開。
          用book.dtd約束book.xml,如果在book.xml的書標簽下添加出版日期,會報錯,因為文檔格式已經固定。
          注意:DTD文件應使用utf-8保存或者encoding="gb2312",否則會報錯。

          引用DTD約束
          xml文件使用DOCTYPE聲明語句來指明它所遵循的DTD文件,聲明語句有兩種形式
          (1)當引用的文件在本地時 ,采用如下方式:
          <!DOCTYPE 文檔根節點 system "DTD文件的URL"> 
          例如:<!DOCTYPE 圖書 SYSTEM "book.dtd">  
          (2)當引用的文件是一個公共的文件時 ,采用如下方式:
          <!DOCTYPE 文檔根節點 public "DTD名稱" "DTD文件的URL">
          例如:<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
           "http://struts.apache.org/dtds/struts-config_1_3.dtd">
           struts2的DTD文件,一般做框架都會用到DTD

          DTD約束語法細節
          元素定義
          屬性定義
          實體定義

          元素定義
          在DTD文件中使用element聲明一個xml元素,語法格式所示:
          <!ELEMENT 元素名稱 元素類型>
          (1)元素類型可以是元素內容或者類型
          如為元素內容:則需要使用()括起來,如
          <!ELEMENT 書 (書名,作者,售價)>
          <!ELEMENT 書名 (#PCDATA)>
          (2)如為元素類型,則直接書寫 ,DTD規范定義如下幾種類型:
          EMPTY:用于定義空元素,例如<br></br>
          ANY:表示元素內容為任意類型
          -----------------------------------------------------
          元素內容可以使用如下方式,描述內容的組成關系用逗號分隔,表示內容的出現順序必須與聲明時一致
          用逗號分隔,表示內容的出現順序必須與聲明時一致。
          <!ELEMENT 書 (書名,作者,售價)>
          用|分隔,表示任選其一,即多個只能出現一個
          <!ELEMENT 書 (書名|作者|售價)>
          在元素內容中也可以使用+,*,?等符號表示元素出現的次數:
          +:一次或多次(書+)
          0:0次或一次(書?)
          *:0次或多次(書*)
          什么都不寫 (書)只出現一次

          也可以使用原括號()批量設置,例
          <!ELEMENT 書((書名*,作者?售價)*|COMMENT)>

          屬性定義
          xml文檔的標簽性需要通過ATTLIST為其設置屬性
          語法格式:
          <!ATTLIST 元素名
          屬性名1 屬性值類型 設置說明
          屬性名2 屬性值類型 設置說明
          ......
          >
          屬性聲明舉例
          <!ATTLIST 圖書
            書名 CDATA #REQUIRED
            售價 CDATA #IMPLED
          >
          對應xml文件:
          <圖書 書名="三國演義" 售價="20">...</圖書>
          <圖書 書名="西游記" 售價="18">...</圖書>
          設置說明:
          #REQUIRED 必須設置該屬性
          #IMPLED 可以設置也可以不設置
          #FIXED:說明該屬性的值固定為一個值
          直接使用默認值:在xml中可以設置該值也可以不設置該屬性值。如果沒設置則使用默認值
          舉例:
          <!ATTLST 圖書
          書名 CDATA #REQUIRED
          售價 CDATA #IMPLED
          類別 CDATA #FIXED "文學"
          評價 CDATA "好"
          >
          -----------------------------------------------
          CDATA表示屬性值為普通文本字符串
          ENUMERATED(枚舉)
          ID,表示設置值為一個唯一值,ID屬性的值只能由字母,下劃線開始,不能出現空白字符
          ENTITY(實體)


          實體定義
          實體用于為一段內容創建一個別名,以后在xml文檔中就可以使用別名引用這段內容
          在DTD定義一個實體,一條<!ENTITY>語句用于定義一個實體
          實體可分為兩種類型:引用實體個參數實體
          (1)引用實體主要在xml文檔中被應用
          語法格式:
          <!ENTITY 實體名稱 "實體內容">: 直接轉變成實體內容
          引用方式:
          &實體名稱;
          舉例
          <!ENTITY name "I am a student">
          .....
          &name;
          (2)參數實體被DTD文件自身使用
          語法格式:
          <!ENTITY % 實體名稱 "實體內容">
          &實體名稱;

           

          在struts1里action標簽必須要設置的屬性:path

          Java代碼  
          1. <!ELEMENT action (icon?, display-name?, description?, set-property*, exception*, forward*)>   
          2. <!ATTLIST action         id             ID              #IMPLIED>   
          3. <!ATTLIST action         attribute      %BeanName;      #IMPLIED>   
          4. <!ATTLIST action         className      %ClassName;     #IMPLIED>   
          5. <!ATTLIST action         forward        %RequestPath;   #IMPLIED>   
          6. <!ATTLIST action         include        %RequestPath;   #IMPLIED>   
          7. <!ATTLIST action         input          %RequestPath;   #IMPLIED>   
          8. <!ATTLIST action         name           %BeanName;      #IMPLIED>   
          9. <!ATTLIST action         parameter      CDATA           #IMPLIED>   
          10. <!ATTLIST action         path           %RequestPath;   #REQUIRED>   
          11. <!ATTLIST action         prefix         CDATA           #IMPLIED>   
          12. <!ATTLIST action         roles          CDATA           #IMPLIED>   
          13. <!ATTLIST action         scope          %RequestScope;  #IMPLIED>   
          14. <!ATTLIST action         suffix         CDATA           #IMPLIED>   
          15. <!ATTLIST action         type           %ClassName;     #IMPLIED>   
          16. <!ATTLIST action         unknown        %Boolean;       #IMPLIED>   
          17. <!ATTLIST action         validate       %Boolean;       #IMPLIED>  

          posted @ 2012-07-27 15:00 chen11-1 閱讀(1002) | 評論 (0)編輯 收藏

          僅列出標題
          共20頁: First 上一頁 8 9 10 11 12 13 14 15 16 下一頁 Last 
          主站蜘蛛池模板: 仁化县| 龙门县| 通州区| 富平县| 桂平市| 佳木斯市| 宁远县| 台州市| 凤翔县| 石景山区| 五莲县| 灵台县| 莒南县| 芒康县| 遵义市| 抚顺县| 嘉禾县| 太康县| 景宁| 吐鲁番市| 绥德县| 中江县| 马尔康县| 德昌县| 抚远县| 个旧市| 云和县| 宣化县| 玛沁县| 林州市| 山阴县| 泾源县| 宜宾市| 宣城市| 苍溪县| 安新县| 江源县| 万安县| 萝北县| 安庆市| 龙南县|