<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    TWaver - 專注UI技術

    http://twaver.servasoft.com/
    posts - 171, comments - 191, trackbacks - 0, articles - 2
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    深入淺出GUI線程安全(三)

    Posted on 2010-09-03 14:10 TWaver 閱讀(1808) 評論(0)  編輯  收藏
    第一第二篇后,GUI線程安全的原理性內容基本就這些了,如果你是搞學術理論研究的基本就不用繼續閱讀下面幾篇我要繼續八卦的內容,下面的內容都是針對具體技術平臺的細節問題了。
    1static void Main(string[] args)
    2{
    3    TextBlock text = new TextBlock();
    4}

    創建個Console程序,敲出上面的和helloworld一樣復雜度的代碼,運行后你估計會懷疑自己的智商,這么簡單的代碼都能搞出異常?

    還真是再簡單問題都有其復雜的一面,我總在想為什么傻人有傻福,因為傻人傻傻的認真對待每個簡單的事情所以搞透了其復雜的本質,所謂的聰明人都去研究哥德巴赫猜想,日積月累傻人掌握了眾多事物本質成了有福之人,所謂聰明者竟然沒搞明白一加一為什么等于二。

     1private InputManager()
     2{
     3    // STA Requirement
     4    //
     5    // Avalon doesn't necessarily require STA, but many components do.  Examples
     6    // include Cicero, OLE, COM, etc.  So we throw an exception here if the
     7    // thread is not STA.
     8    if(Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
     9    {
    10        throw new InvalidOperationException(SR.Get(SRID.RequiresSTA));
    11    }

    看看System.Windows.Input.InputManager的代碼實現你就明白了,原來TextBlock的創建要求在STA環境中,你要問我啥叫STA,我喜歡將其簡單理解為這玩意兒就是我們前面提到的EDT,也就是那個全局唯一的UI Thread,具體的解釋你可以看Component_Object_Model#Threading_in_COM的解釋,當年讀潘愛民翻譯的《COM本質論》差點讓我沒了繼續當程序員的勇氣,以下引用了一段話你就看著玩就行

     
    There are three types of Apartment Models in the COM world: Single-Threaded Apartment (STA), Multi-Threaded Apartment (MTA), and Neutral Apartment. Each apartment represents one mechanism whereby an object’s internal state may be synchronized across multiple threads.
    The Single-Threaded Apartment (STA) model is a very commonly used model. Here, a COM object stands in a position similar to a desktop application’s user interface. In an STA model, a single thread is dedicated to drive an object’s methods, i.e. a single thread is always used to execute the methods of the object. In such an arrangement, method calls from threads outside of the apartment are marshalled and automatically queued by the system (via a standard Windows message queue). Thus, there is no worry about race conditions or lack of synchronicity because each method call of an object is always executed to completion before another is invoked. 

    上面的一行代碼其實已經說明了問題Thread.CurrentThread.GetApartmentState() != ApartmentState.STA,也就是main啟動運行的線程并不是EDT,回想一下WindowsForms和WPF的應用程序的main是怎么寫的,是的就是這個[STAThread]起的作用,把上面代碼加上這個[STAThread]你就不會再懷疑自己智商了。

    1[STAThread]
    2static void Main()
    3{
    4     
    5}

    《Applications = Code + Markup》這本是我學習WPF的第一本書,講解思路非常符合傳統程序員口味,上半本先完全用OO的方式解釋了WPF組件的來龍去脈,下半本才開始設計XAML的標簽應用,說實話我很看不慣現在的快餐式書籍,一上來就是XAML用戶連WPF組件Dependency Properties這種最重要的新機制都完全不明白的情況下就開始寫項目,同樣的還有一上來就開始鼓吹如何用MXML快速創建Flex程序,本末倒置不介紹背后ActionScript語言實現原理的書籍,更有一大堆歷史杯具人物寫了多年JSP不知道啥是Java的OO。

    前幾天逛書店發現蔡學庸也翻譯了《Applications = Code + Markup》一書,剛畢業時買過他的一本經典《Java夜未眠》,那時候作為個junior程序員的我手頭也幾個錢,晚上也沒法去新天地泡mm的方式夜未眠,只好翻翻學庸兄的《Java夜未眠》,不過這些年薪水提高了反而不去書店買書了,原因很簡單譯書上得不到最新的技術資料而且翻譯往往后失去作者的原味,相信《紅樓夢》的譯書很難接近原著的味道,扯遠了,我不是要推銷《Applications = Code + Markup》,更不是要打擊蔡學庸譯書的銷量(我還是很尊重且喜歡訂閱學庸兄的blog,如果學庸看到小弟此文希望能有機會交個朋友),只是想引用書中一段話幫助大家理解:

    In any WPF program, the [STAThread] attribute must precede Main or the C# compiler will complain. This attribute directs the threading model of the initial application thread to be a single-threaded apartment, which is required for interoperability with the Component Object Model (COM). “Single-threaded apartment” is an old COM-era, pre-.NET programming term, but for our purposes you could imagine it to mean our application won’t be using multiple threads originating from the runtime environment.

    使用TWaver Java的客戶應該有印象,TWaver Java Demo的啟動代碼和地球上99%的Swing的main代碼不一樣,套了個SwingUtilities.invokeLater,曾經有個客戶程序啟動再大部分機器上都正常,結果在一臺雙核(N年前雙核可是很洋相配置)的機器啟動總出錯,去現場幫忙找原因時我查的第一行代碼就是main的啟動代碼,發現用戶直接就在main里面創建各種UI組件,同時還起了Thread做各種業務,我就讓他改成和TWaver Demo一樣,啟動時套了個SwingUtilities.invokeLater,你猜怎么樣我竟然“被”允許回家了,這是我在賽瓦這些年最短的現場支持經歷,像我這種不敢坐飛機的(去年做了38個小時火車去了哈爾濱培訓客戶)做了十幾個小時的火車竟然現場待了幾分鐘就回家了,實在是虧啊。

    1public static void main(String[] args) {
    2    SwingUtilities.invokeLater(new Runnable(){
    3        public void run() {
    4            Demo.init();
    5            DemoFrame demoFrame = new DemoFrame();
    6            demoFrame.setVisible(true);
    7        }

    8    }
    );
    9}

    很簡單,因為main啟動的函數并不是Swing的事件派發線程,SwingUtilities.isEventDispatchThread()你可以調用該函數測試一下,而地球99%的代碼直接非EDT里面做UI的工作時極其危險的,大部分程序都是初始化界面然后show就結束了,這樣基本能僥幸不出錯,但如果你調用了show之后再有代碼在執行,而且是操作到UI組件的地方拿基本必然會導致問題,但為了您的生命安全還請遵守GUI線程安全規則。這里有更多的解釋可以參考:

    public class MyApplication {
    public static void main(String[] args) {
    JFrame f = new JFrame(“Labels”);
    // Add components to
    // the frame here…
    f.pack();
    f.show();
    // Don’t do any more GUI work here…
    }
    }
    All the code shown above runs on the “main” thread. The f.pack() call realizes the components under the JFrame. This means that, technically, the f.show() call is unsafe and should be executed in the event-dispatching thread. However, as long as the program doesn’t already have a visible GUI, it’s exceedingly unlikely that the JFrame or its contents will receive a paint() call before f.show() returns. Because there’s no GUI code after the f.show() call, all GUI work moves from the main thread to the event-dispatching thread, and the preceding code is, in practice, thread-safe. 

    另外我挺喜歡現在.NET的線程安全問題上再底層框架做的檢查工作,就像剛才Console操作TextBlock的代碼,很容易程序員就能知道問題所在,而Swing這點上是最讓我不滿意的地方,你不提示檢查我這些在普通線程操作UI組件就算了,某些情況下Swing還自作聰明的在內部幫你SwingUtilities.invoke***,結果常常導致很多客戶質問我為什么我在普通線程調用revalidate()不出錯,你們還非得讓我以這么丑陋的代碼方式到處去SwingUtilities.invoke,我覺得Swing這樣的實現會誤導程序員放松對線程安全的戒備,Swing僅僅在很少很少很少的函數上做了判斷內部處理,如果大家覺得JComponent.revalidate()可以隨意調用,那豈不TableModel、TreeModel…包括TWaver的DataBox和Element都可以不管EDT隨意調用了,所以這點上.NET嚴謹的判斷還是能讓程序員盡早的規避了很多線程安全問題

     1public void revalidate() {
     2    if (getParent() == null{
     3        // Note: We don't bother invalidating here as once added
     4        // to a valid parent invalidate will be invoked (addImpl
     5        // invokes addNotify which will invoke invalidate on the
     6        // new Component). Also, if we do add a check to isValid
     7        // here it can potentially be called before the constructor
     8        // which was causing some people grief.
     9        return;
    10    }

    11    if (SwingUtilities.isEventDispatchThread()) {
    12        invalidate();
    13        RepaintManager.currentManager(this).addInvalidComponent(this);
    14    }

    15    else {
    16        Runnable callRevalidate = new Runnable() {
    17            public void run() {
    18                revalidate();
    19            }

    20        }
    ;
    21        SwingUtilities.invokeLater(callRevalidate);
    22    }

    23}
    今天要講的就這些內容,不知道昨天提到TWaver的FileTreeDemo里面還有個多線程的細節,你有沒有注意到tree在加載文件是還能看到gif的loading圖標,你只要打開tree.setEnableAnimation(true)開關,隨時隨意間任何element.setIcon(“/demo/tree/file/loading.gif”)設置上任何gif圖標,twaver將透明自動的識別gif動畫圖標,并且讓tree上的icon動畫起來。這還沒啥,有一回我看到用戶啟動畫面竟然有很酷動畫的splash screen,我問用戶是不是嵌入了Flash,用戶說:“用的就是你們的Network做啟動界面,只不過放了一個GIF的大Node做主啟動界面而已,賽瓦真該開除了你這個傻B,還號稱TWaver Evangelist,丟人也不能丟這么大啊”

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲AV日韩AV永久无码久久| 亚洲国产av一区二区三区丶| 亚洲精品视频在线观看免费| 亚洲日日做天天做日日谢| 四虎国产精品免费视| 免费看搞黄视频网站| 亚洲欧洲专线一区| 亚洲毛片αv无线播放一区 | 最近2019中文字幕免费直播| 国产人成亚洲第一网站在线播放| 亚洲国产精品综合久久一线| 日韩av无码久久精品免费| 亚洲妇女无套内射精| 亚洲大成色www永久网站| 免费鲁丝片一级在线观看| 在线观看人成视频免费无遮挡| 亚洲成a人片在线看| 久久精品国产精品亚洲下载| 日韩中文字幕精品免费一区| 一个人晚上在线观看的免费视频| 亚洲免费二区三区| 亚洲伊人久久大香线蕉综合图片| 在线免费一区二区| 久久99国产综合精品免费| 一级做a爰片性色毛片免费网站| 亚洲va在线va天堂va手机| 亚洲av无码不卡| 亚洲AⅤ视频一区二区三区| 国产va免费精品观看精品| 国产无遮挡又黄又爽免费网站| 亚洲αⅴ无码乱码在线观看性色| 亚洲高清视频在线播放| 亚洲人成精品久久久久| 免费a在线观看播放| 台湾一级毛片永久免费| 人人揉揉香蕉大免费不卡| 一本岛v免费不卡一二三区| 亚洲av日韩av永久在线观看| 亚洲免费闲人蜜桃| 亚洲三级电影网站| 亚洲AV无码精品色午夜在线观看|