作為一名TWaver Evangelist,我的工作目的就是通過與客戶的交流、培訓甚至現場支持等方式幫助用戶將TWaver更好地應用到客戶項目中,TWaver是這么一款橫跨Java、Web、Flex和.NET等多種技術平臺的GUI圖形組件,因此我的工作內容簡單的說就是:幫助客戶正確使用GUI。
提到GUI線程安全,這是我最想談也最不想談的話題,想談因為此問題不說明白,用戶不清楚項目架構設計之初GUI最需要考慮的問題,往往后期集成測試上線時會出現災難性的后果;不想談因為這個話題太大了,從UI單線程的基本事件派發原理,到Swing、SWT、Flex、Silverlight、WPF甚至是Swing in EclipseRCP,Silverlight in windowsFroms,Applet in MFC等這種“雜交”的情況,這個話題一展開沒有幾個小時剎不住車,甚至需要陷入幫Sun、Adobe、MS向客戶解釋為什么Swing和Silverlight不能設計成線程安全,Flex和JavaScript為什么不提供線程的問題。
anyway,我桌面已擺著一塊大面包,一大杯濃茶(我哥常鄙視我這樣的喝法糟蹋了好茶葉),希望能有精力一口氣把這該死的問題一次性的解釋透徹。
總得來說目前幾乎所有主流的GUI技術采用的都是Single UI Thread的實現方式,簡單說你操作任何組件都必須在那個唯一的UI Thread里面進行,否則就會出錯,這里指的也不僅僅是UI組件,大部分時候我們所指的是綁定UI組件的Model部分,因為大部分GUI技術無論是Swing/SWT的MVC,或Flex和TWaver那樣的MVP,或微軟在WPF和Silverlight中采用的MVP的變異MVVM,這些事件機制最終會導致你對Model層的修改實則間接的也是修改了UI組件,因此在非UI Thread的所有任何其他thread地方你絕對不能碰UI組件已經其所綁定的Model。
用TWaver的話說:你操作network,tree,table,sheet,list,chart包括已經綁定這些view的databox、element、selectionmodel、alarm、alarmmodel等都必須確保代碼運行在UI Thead中。這里有個地方需要注意我指的是已經綁定了View的模型,由于TWaver的DataBox是可以用xml的文本和Serializable的二進制兩種方式進行序列化,因此很多用戶會把twaver的databox數據構建放在后臺進行,包括TWaver Web整個模型是在J2EE后臺容器操作,這種情況下你只要保證單線程操作即可,并不要求這個線程必須是UI Thread,因為你還沒有綁定View因此沒有UI Thread線程安全的限制。
有些人問為什么要有這些限制,為什么TWaver不能設計成現場安全的,其實我們的回答和Sun(現在的Oracle)的解釋是一致的Why did we implement Swing this way?,同樣你也可以找到Why did we implement SWT,Flex,WindowsForms,Silverlight,WPF….this way的類似解釋的文章,并不是我們逃脫責任將痛苦留給客戶,而是因為我們認為多線程的GUI框架非常困難,更不利于用戶的開發調試,甚至由于需要進行的各種同步保護反而降低了整體GUI交互效果。
簡單說一個存著number元素的list讓你求sum,如果有多線程并發在你for循環的時候動態修改你怎么辦,你會說加上lock鎖定這個list不就得了,如果這個list非常長需要運行很長時間那豈不其他人都被你堵住了,你會想的想java.util.concurrent的實現那樣分成更多的塊來操作,老大你看看ConcurrentHashMap的一千多行代碼才僅僅解決了map問題,你還會說看看微軟C#4的強大的并行處理Parallel.ForEach函數,即使是這個也僅僅解決了無狀態和沒有太多耦合邏輯的運算分解,對于復雜的GUI耦合邏輯目前還沒有靈丹妙藥,Parallel.ForEach也是需要讓你修改代碼的,現在的本子動不動就配上4個8個CPU,但跑在上面的GUI程序性能不會比當CPU的強,因為需要GUI密集運算工作時依然只有一個CPU在工作。
這些年并行計算呼聲很高,google這樣的巨人已經讓我們老百姓感受到了并行計算的優勢,但回到GUI我們依然無法輕松、廉價和透明的體驗到并行的好處,也許有那么一天會到來,但目前階段我并不渴望,以目前的語言類庫基礎如果采用并發的方式只會讓我們的調試開發更痛苦,當然最重要的是現在的主要瓶頸已經不是GUI的組件了,而是數據DATA,從海量的數據中查詢獲取到你需要的DATA這個過程才是瓶頸,良好的GUI框架設計不應該將數據的獲取與界面的呈現耦合得不可分離,就像TWaver可以秒級的加載萬甚至10萬以上的圖元,但最大的瓶頸是用戶如何更短的時間去獲取和傳輸這些數據。
再看看現在熱賣得脫銷iphone4(一萬多甚至最高兩萬二的天價讓我想起當年的大哥大時代)和IPad,對應這樣的硬件配置用于瀏覽網頁,受發郵件,聽歌看碟,玩玩小游戲已經搓搓有余了,大家抱怨的是信號門,抱怨的是不堪重負的AT&T網絡,題外話Cocoa同樣也不是線程安全的哦:
因此現階段我們唯一能做的就是老老實實遵守Single UI Thread設計帶來的限制,這個Thread有很多叫法,在Swing里面稱之為EDT(Event Dispatcher Thread),以下的文章中我們都會簡稱之EDT。