小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

JavaEE組件的并發(fā)與無(wú)狀態(tài)

 CevenCheng 2011-09-05

JavaEE組件的并發(fā)與無(wú)狀態(tài)

sulong 于 2009-01-05說兩句 ?

并發(fā)與線程安全

串行運(yùn)行時(shí)正確的程序在并發(fā)運(yùn)行時(shí)可能會(huì)出錯(cuò),這是由于并發(fā)運(yùn)行的多個(gè)任務(wù)(進(jìn)程或線程)之間共享了變量。在Java EE環(huán)境下很多的組件最終都是在多線程環(huán)境下并發(fā)運(yùn)行的,應(yīng)該牢記住這一點(diǎn),避免發(fā)生詭異的錯(cuò)誤。在上個(gè)項(xiàng)目中,我們的程序就出現(xiàn)過詭異的錯(cuò)誤,在并發(fā)量小的測(cè)試環(huán)境下,它很少出現(xiàn),但是隨著并發(fā)量的增大,它出現(xiàn)的次數(shù)增多。經(jīng)查,發(fā)現(xiàn)如下類似代碼:

    public class SomeServlet extends HttpServlet {
        private SomeType someVariable;

        public void doPost(HttpServletRequest req, HttpServletRespons rsp) {
            method1();
            method2();
        }

        void method1() {
            ...
            someVariable = someValue;
            ...
        }

        void method2() {
            ...
            someVariable = someValue;
            ...
        }
    }

method1() 和method2()都訪問到了someVariable,而且程序員的本意是想在method2()使用由method1()產(chǎn)生的 someVariable,但是Servlet可能被多個(gè)線程共享,上面的代碼不能正常工作。當(dāng)Servlet容器用thread1和thread2兩個(gè)線程來(lái)服務(wù)兩個(gè)請(qǐng)求request1和request2,而thread1和thread2使用了同一個(gè)SomeServlet對(duì)象,如果JVM在 SomeServlet在執(zhí)行到method1()后和method2()前時(shí)發(fā)生線程間的切換,那么就很可能導(dǎo)致出錯(cuò),比如:thread1.method1()->thread2.method1()->thread1.method2()->thread2.method2()。實(shí)例變量和類變量都是在線程間共享的,而方法內(nèi)的局部變量和參數(shù)是不會(huì)被共享的,所以要處理這個(gè)問題,最簡(jiǎn)單的方法是通過方法參數(shù)來(lái)傳遞 someVariable,而不是通過實(shí)例變量。所以這段程序改成這樣就可以了:

    public class SomeServlet extends HttpServlet {

        public void doPost(HttpServletRequest req, HttpServletRespons rsp) {
            SomeType someVariable = method1();
            method2(someVariable );
        }

        SomeType someVariablemethod1() {
            ...
            return someValue;
        }

        void method2(SomeType someVariable) {
            ...
            someVariable = someValue;
            ...
        }
    }

通過synchronized等并發(fā)訪問控制機(jī)制也可以解決這個(gè)問題,但是我覺得上面的方式是最直觀的。也許有人會(huì)說后面的代碼比前面的看起來(lái)要難看,不夠面向?qū)ο?。這里不討論怎樣才是面向?qū)ο?,或者面向?qū)ο蠛貌缓???傊笳呤钦_的,前者是錯(cuò)誤的,沒有正確性的程序是沒有意義的。

被過線程共享而不會(huì)出錯(cuò)的對(duì)象,被稱之為線程安全的。顯然Servlet不是線程安全的,而且還有很多組件也不是線程安全的,比如HttpSession。在上個(gè)項(xiàng)目中,我們使用JAXB來(lái)處理XML,每次使用時(shí)都創(chuàng)建一個(gè)JAXBContext對(duì)象,后來(lái)發(fā)現(xiàn)創(chuàng)建JAXBContext的代價(jià)是相當(dāng)?shù)母?,于是我們想把它緩存起?lái)在整個(gè)應(yīng)用程序范圍內(nèi)使用,幸好我們使用的JAXBContext的實(shí)現(xiàn)是線程安全的,可以放心的被多個(gè)線程共享。

有狀態(tài)與無(wú)狀態(tài)

有狀態(tài)組件是這樣一種組件,組件調(diào)用者的返回結(jié)果會(huì)依賴于這個(gè)組件之前或正在受到的調(diào)用。無(wú)狀態(tài)的組件則相反,調(diào)用者的返回結(jié)果只和本次調(diào)用相關(guān),所有調(diào)用者的調(diào)用過程不會(huì)影響到其他調(diào)用者。舉例來(lái)說,someComponent組件的getLatestCaller()返回上一次的調(diào)用者,這個(gè)行為的返回值總會(huì)和上一次的調(diào)用者相關(guān),這樣的組件就是有狀態(tài)的。假如有個(gè)組件math有個(gè)方法為add(x,y),返回x+y的值,那么無(wú)論之前被哪個(gè)調(diào)用者調(diào)用過,math.add()的返回值只和本次調(diào)用的參數(shù)相關(guān),這樣的組件是無(wú)狀態(tài)的。無(wú)狀態(tài)的組件是線程安全的,因?yàn)楸粍e的調(diào)用者調(diào)用并不會(huì)影響到本次的調(diào)用結(jié)果。

除非有必要,否則應(yīng)當(dāng)盡量把你的程序組件實(shí)現(xiàn)成無(wú)狀態(tài)的。在spring, seam, ejb里都有無(wú)狀態(tài)的組件。不同的框架在如何實(shí)現(xiàn)無(wú)狀態(tài)方面各不相同。最簡(jiǎn)單的實(shí)現(xiàn)方法就是為無(wú)狀態(tài)組件做一個(gè)包裝,每次調(diào)用組件的方法時(shí),都由包裝類生成一個(gè)新的對(duì)象來(lái)處理,這樣實(shí)際上就不再任何的調(diào)用者之間共享被調(diào)用者的實(shí)例,實(shí)現(xiàn)了無(wú)狀態(tài)。比如:

    public interface SomeInterface {
        public SomeType doMyBusinness(SomeArg arg);
    }

    public class SomeStatlessComponent implements SomeInterface {
        public SomeType doMyBusinness(SomeArg arg) {
           ...
        }
    }

    public class SomeStatlessComponentWrapper implements SomeInterface {
        public SomeType doMyBusinness(SomeArg arg) {
           return new SomeStatlessComponent().doMyBusinness(arg);
        }
    }

如果實(shí)例化組件的代價(jià)是昂貴的,用一個(gè)對(duì)象池緩存組件實(shí)例,并在每次從池中取對(duì)象時(shí)清空對(duì)象的狀態(tài)可能是個(gè)更好的辦法。其實(shí)只要遵循簡(jiǎn)單的原則,就很容易實(shí)現(xiàn)無(wú)狀態(tài),就是不使用實(shí)例變量或類變量,或者只使用只讀的實(shí)例變量或只讀類變量。這樣的組件用單例就可以實(shí)先無(wú)狀態(tài)。

由于實(shí)現(xiàn)上的差別,有些框架根本就不會(huì)做過多的努力來(lái)保證組件的無(wú)狀態(tài)性,相反他們把責(zé)任交給了程序員。作為組件的創(chuàng)作者,如果你確定你要的是無(wú)狀態(tài)的組件,那么只使用只讀的實(shí)例變量或類變量,是個(gè)明智的選擇。

相關(guān)文章:

  1. JAXB中如何利用繼承生成XML
  2. 當(dāng)return遇到finally
  3. 最快的計(jì)算子字符串出現(xiàn)次數(shù)程序
  4. 用hibernate映射時(shí)遇到的問題
  5. 靜態(tài)域的作用范圍
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多