前言
html
其實事情的通過也許會複雜了點,這事還得從兩個月前開始說。那天,我果斷不幹IT支援。那天,我立志要作一個真正的程序猿。那天,我26歲11個月。那天,我開始看Android。那天,我一邊叨唸着有朋自遠方來,一邊投身了JAVA的懷抱。那天,一切將會改變。java
好吧,反正總的來講就是時隔4年半,我又開始搞JAVA了。Eclipse仍是Eclipse;NetBeans仍是NetBeans;Java被收以後已經來到了7,如今是8;在入手了幾本JAVA的書籍後發現《JAVA編程思想》仍是這麼偉大;開始了新的路途--Android。程序員
下面可能會涉及到一些跟其餘框架或者語言比較的狀況,好比當下挺火的HTML5,好比愈來愈火的U3D,好比以前一直從事的WEB應用。而後是個人老朋友JAVA,還有他介紹給我認識的新朋友Android跟以前我或深或淺涉獵過的這些奇奇怪怪的東西作一些比較。固然,主要論述的都是JAVA關於線程這塊的一些或技術或心路的歷程吧。編程
我與多線程的那些事設計模式
先不從項目說,先說說我對多線程的恐懼。遙想當年讀書的時候,JAVA課程設計,老溼給了一個題目,我以爲沒啥難度,而後本身立了一個題目,叫兩人對戰遊戲,就是控制兩我的跑來跑去而後有攻擊防護和技能三個按鍵,反正就是很弱智的那種。而後老溼說要求用TXT來編,用cmd來調,給一個仍是兩個星期仍是一個月時間去弄,反正我就在最後一個星期管這事。而後我拿着一本JAVA編程思想,兩天就把UI寫起來,而後就是地獄般的4天,各類各樣稀奇古怪的BUG,debug以後觸發了更多的bug,而後到了交任務的時候我已經燃燒殆盡了~ 而後因爲當初沒選老溼的題目已經讓老溼很不爽,如今作的這個東西奇奇怪怪的固然被狠批一頓。給了個60多分了事。過後我本身努力了一把,而後就放棄了,刪源碼,刪程序,各類刪~ 而後各類自卑,各類以爲本身就是個嗶嗶,而後看到多線程就尿了~
數組
而後到了工做寫的第一個系統,庫存ERP系統(這裏很感激公司能給一個實習生這麼大的空間去發揮啊~)。忽略掉前面那些技術選型啊,噼裏啪啦的東西以後到了數據訪問這一環,我半天時間就寫完了。用的是ASP.NET。可是這裏出問題了,由於我用的是直接提交一條SQL語句去執行操做的,而後根據返回的值來斷定後面執行的SQL操做。那時我忽然想到一個問題,若是兩個用戶同時用個人SQL語句去操做,而操做的資源這個時候斷定是不對的,可是可能因爲另一個用戶的同時操做使得這個斷定經過了,這怎麼弄?(簡單來講就是一個同步的問題,那時候還不知道~)安全
而後就是.NET實現原子性啊,.NET實現事務啊噼裏啪啦的東西。到了最後,我把業務邏輯寫在了T-SQL存儲過程裏面,所以這裏面的東西充斥着begin tran a; submit tran a; rollback tran a;而後還特地研究了T-SQL事務處理的遞歸性(具體能夠參閱我以前博客的這篇文章:SQL存儲過程遞歸下的事務處理(自己的缺陷仍是蠻大的) )。而後各類噼裏啪啦以後,寫T-SQL各類順手。而後各類各樣的邏輯所有寫存儲過程,而後練就了一雙寫T-SQL的好手~~多線程
在日後是隨着經驗值的上漲,我開始密謀架構ERP內核的時候作的單例模式,用於管理用戶登陸信息。這個時候出現了一種叫線程安全的單例模式,而後就是lock(object){...},不求甚解,直接就上了。關於「線程安全的單例模式」不懂的能夠直接複製去問度娘。那時作出來的時候特囂張,雖然只知其一;不知其二,也去忽悠別人了~ 反正是能跑,你管俺是真懂的仍是蒙中的~ 架構
直到……app
初體驗
各類蛋疼的人事,各類無聊的糾紛,各類倔強的淚水以後,俺從事Android了,俺搞JAVA了~
說下Android跟U3D UI線程方面的不一樣吧,純我的或別人觀點,有錯的話請溫柔地指出。U3D的UI線程咱們公司的一位專門從事這個領域的哥們說U3D的線程就是一個大輪詢,往裏面塞任務。簡單來講U3D的UI是跑一條線程的(其實想一想也是合理的,由於U3D支持多平臺發佈,其中就包括了Web平臺,而JAVAScript就是單線程的)。而Android的UI線程是多線程的,其餘線程想要調用Android的UI線程,那就得用handler了,貌似是個鉤子的方式作嵌入(詳細狀況能夠參考這裏: Android之Handler用法總結 還有鉤子的介紹,設計模式之:模板模式)。那麼從上面的信息得知Android的UI極有多是維護一個線程池的。(純屬我的推斷,未經考察證明)而Android除了上面的Handler(在其餘線程跑UI)以外貌似還提供了一些不錯的在UI內部跑其餘線程的支援。
而後雖然瞭解了上面的這些,可是項目的內核還得用JAVA多線程來作,並且跟UI目測沒有半毛錢關係。所以吧,就只能老老實實打基礎了。有個同事的QQ簽名是:當你的才華不足以支撐你的野心時,那你就得多看點書。我以爲頗有道理,所以我看書……
Runnable&Thread
開始好多人都說JAVA多線程就是實現Runnable接口或者寫Thread類。可是這種說法有時會混熬咱們的思惟,反正我那時候就是把這二者當成平衡的來看,但其實從如今的應用來講Runnable更多的應該比喻成一個任務(Task),而Thread是管理這個任務的容器。有興趣的人能夠去搜下Thread.start()和Runnable.run()之間的區別。所以不少寫過多線程的程序員都會有這種感受:Runnable用的比Thread要多。而在《JAVA編程思想》裏面更是推薦你們用所謂的線程池來管理本身的線程。這裏引出了一個概念:線程池。這裏能夠得出一個結論:線程的管理和線程自己已經分離了。所以這裏叫線程已經顯得不合適了,這時候換一個稱呼可能更加的有助於咱們對這個事情的理解。好比把一個Runnable的實例叫「任務」。
1 private Runnable aNewTask = new Runnable() 2 { 3 @Override 4 public void run() 5 { 6 //跑一些奇怪的東西 7 System.out.println("哈哈"); 8 } 9 } 10 ExecutorService exec = Executors.newCachedThreadPool(); 11 exec.execute(aNewTask); 12 exec.shutdown();
上述就是把一個任務aNewTask放到exec的一個池裏面跑,shutdown是關閉池,固然也能夠不關閉啦。池有不少種,具體能夠看文檔或者JAVA編程思想吧。
生產者-消費者模型
這種模型適合的情景:一個資源,兩條線程,一條線程負責讀,一條線程負責寫。
具體能夠參閱下面的文章: java實現生產者消費者問題
文章裏面提到幾種方法,我用到第三種,所以下面是基於JAVA的堵塞隊列LinkedBlockingQueue來討論的。這裏的生產者-消費者模型說的比較少,可是他是我整個模型的核心思想。這裏有幾點我項目的時候犯過的錯這裏提出來一下:
1. LinkedBlockingQueue裏面我存的是一個數組,就是說這是一個數組的隊列。而每當我從另外的地方接受了數據以後就傳入這個隊列,這時候須要把這個傳入的數組clone()一次。由於直接傳入的那只是一個引用,而非實體,極有可能這個引用的實體在遞交給隊列以後就會銷燬了。這時就只剩下一個地址了。
2. LinkedBlockingQueue是線程安全的,可是若是想要確保一次任務或者一個循環裏面屢次調用的時候不受干擾,那麼仍是得用同步鎖synchronized去鎖定循環體執行的代碼。有個資深程序員,同時也是我同窗,說:儘可能不要用synchronized去鎖定資源。而兩一位更加資深的工程師也說鎖會產生格外的損耗,能不用就不用。可是顯然到了我項目裏面還得要讀寫的時候鎖死,不然數據就會刷的不整齊了~ 刷不整齊,小夥伴們又有意見了~ 如今想一想,其實也真沒有鎖定的必要啊~ 至於數據會不會丟幀就要留給測試了~。
通過測試: 是能夠不用同步鎖的~~ 仍是那個更加資深的工程師的一句: 合理的安排流程其實能夠不用那麼多鎖的~
3. 雖然跟這個模型不相干,可是仍是記錄一下。在實施的過程當中,我機(dou)智(bi)地把相似於 exec.execute(aNewTask); 這種語句鎖了。而後症狀就是必需要等這個任務執行完了,這個鎖別人的線程纔會獲得釋放~。。可伶我這個一秒鎖人家一下的社會青年啊~ 鎖出翔了~
項目
先上一張最終的收發設計圖吧~
中間那條豎線的意思是接受一個響應的時候才發送下一條數據,夜已深~ 很少介紹項目的細節了。由於整個項目的實施過程基本能夠另外再起一篇長文了。好比最開始思考的無堵塞模型(這個很是好玩~~),而後後來編碼初版的基於Channel的發送堵塞模型,而後發現原來下面的東西沒有想象中的強悍(羞~),作成這一版的基於Module的發送堵塞模型。好吧寫到這裏感受已經在放嘲諷了~
總結
1. 多線程很好玩,思考程序很開心。
2. 帥氣的喊一句,當手撫鍵盤的時候,吾已爲神。
3. 白賴先生聽到以後投來一個看手(S)表(B)的眼神~
-- 原創的喲,轉載請加出處喲 http://www.cnblogs.com/gssl/p/3854512.html 雖然沒什麼人轉的喲 呵呵--