java加锁多线程改为单线程_GUI为什么不设计为多线程(用户事件和底层事件的流程是相反的,每层都加锁效率太低,共用一把锁那就是单线程)...
在我們這批新人轉正評審的時候,我師父問了我的小伙伴一個問題:為什么一些更新界面的方法只能在主線程中調用?師父沒有問我這個問題,讓知其然但不知其所以然的我有種僥幸逃過一難的心情。我想如果回答那是因為Android?GUI庫是單線程消息機制的,更新界面的操作必須放到主線程中執行,那師父可能繼續問為什么Android?GUI要設計成單線程的,我就不知道了。
為什么它非得設計為單線程的?多線程不是更好嗎?帶著點好奇感和求知欲以及鄙視權威的無畏精神我在google中展開了搜索,并最終找到了一個令我滿意的解釋,欣喜之余將我的理解分析給大家。
單線程消息隊列機制
首先我還是說一下我對GUI單線程消息隊列機制的理解,這是我大學里幾年編程經驗賺來的知其然的部分。
Android、Swing、MFC等的GUI庫都使用單線程消息隊列機制來處理繪制界面、事件響應等消息,在這種設計中,每個待處理的任務都被封裝成一個消息添加到消息隊列中。消息隊列是線程安全的(消息隊列自己通過加鎖等機制保證消息不會在多線程競爭中丟失),任何線程都可以添加消息到這個隊列中,但是只有主線程(UI線程)從中取出消息,并執行消息的響應函數,這就保證了只有主線程才去執行這些操作。
單線程消息隊列機制存在一個問題:消息響應函數中不能有耗時長的、計算密集型的操作,因為主線程在努力地處理這樣的操作的時候就無法去處理其它的積壓在消息隊列中的繪制消息、事件消息了(一個消息處理完了主線程才會去隊列中取下一個消息),這時候就會出現按鍵無響應、點擊無反應的情況。
但這個問題有完美的解決方案,我們可以在消息響應函數中啟動另一個工作線程(Worker?Thread)來執行耗時操作,這樣在線程啟動起來后這個消息就算處理完了,主線程可以取下一個消息了,這時候主線程和還未執行完計算任務的工作線程就在操作系統的調度下并駕齊驅地狂奔了(調度算法會保證兩個線程并發或并行地執行,不會專寵某個線程)。
一般我們在耗時任務執行完后還要更新界面展示計算的結果,由于我們不能直接在工作線程中更新界面,所以可能有些小伙伴直接在消息響應函數中線程start后就接著調用join來等待線程結束以更新界面,這其實相當于把耗時任務直接放在主線程去執行,因為在消息響應函數中join其實就是主線程在join,積壓的消息是得不到處理的。正確的處理辦法是將耗時任務改為異步通知機制,即工作線程向消息隊列中添加消息以通知主線程耗時任務完成了,這樣主線程在啟動工作線程后就不需要主動地去調查任務的進展了,“任務結束的時候它會通知我的”,主線程如是說。
工作線程向主線程的消息隊列添加消息的常用方法如下:
l?Android:Acitvity.runOnUiThead、Handler.post、AsyncTask
l?Swing:SwingUtilities.invokeLater
l?Win32、MFC:自定義用戶消息,在工作線程中PostMessage
GUI為什么不設計為多線程
大部分的GUI?toolkits都是設計為上面的單線程消息隊列機制,為什么不設計為多線程的呢?如果GUI是多線程的,CPU又是多核的話,多個CPU核心可以并行地執行繪制等操作,界面響應的速度應該是成倍提升的;而且就算是其中有多線程共享的資源加鎖不就行了嗎?
在google搜索的過程中我看到了負責Swing開發的一個大師的一篇博客《Multithreaded?toolkits:?A?failed?dream?》:
從中我了解到開發多線程的GUI?toolkits是一件吃力不討好的事,不僅開發難度大Bug多多,用起來也未必可以獲得理想中的效果,其中的死鎖和競爭,大師們也感到頭疼。
多線程GUI加鎖困難
為什么這么困難?大師講了一個例子,我們通過用戶級的代碼去改變界面如TextView.setText走的是個自頂向下的流程:
而系統底層發起的如鍵盤事件、點擊事件走的是個自底向上的流程:
這樣就麻煩了,因為為了避免死鎖,每個流程都要走一樣的加鎖順序,而GUI中的這兩個流程卻是完全相反的,如果每一層都有一個鎖的話加鎖就是個難以完成的任務了,而如果每一層都共用一個鎖的話,那就跟單線程沒區別了。
于是GUI?toolkits的開發者就“不負責任”地把GUI設計成了單線程消息隊列機制,然后他們還說界面更新一般不是瓶頸,單線程足夠了。然后我瞬間想到了3D游戲,單線程對于3D應該是很吃力的,但實際上負責3D繪制的是顯卡的GPU,GPU不像CPU那樣事無巨細、事必親躬、鞠躬盡瘁、死而后已,只負責畫好它的圖就可以了,所以并行起來不是件困難的事。
http://blog.csdn.net/liuqiaoyu080512/article/details/12895005#t1
總結
以上是生活随笔為你收集整理的java加锁多线程改为单线程_GUI为什么不设计为多线程(用户事件和底层事件的流程是相反的,每层都加锁效率太低,共用一把锁那就是单线程)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux性能分析top iostat
- 下一篇: IOS – OpenGL ES 调节图像