一盏触、引言
古人云: "聽(tīng)君一席話(huà),勝讀十年書(shū)" .可想而知"聽(tīng)人說(shuō)話(huà)"的重要性块饺。但我這里只是想強(qiáng)調(diào)聽(tīng)技術(shù)人員講話(huà)的重要性,"多聽(tīng)"總比"多看"來(lái)得快,多聽(tīng)別人講,總比自己講要好,即使別人所說(shuō)的是謬論也好,以訛傳訛也罷,我覺(jué)得都有必要一聽(tīng),還可以順便檢驗(yàn)一下你的知識(shí)是否牢固,何樂(lè)而不為呢?獨(dú)自一個(gè)人啃書(shū)本上的知識(shí)確實(shí)會(huì)顯得很空洞,有的書(shū)又比較偏理論,需要耗費(fèi)大量的時(shí)間去理解授艰、消化,所以一本書(shū)的整個(gè)知識(shí)脈絡(luò)對(duì)于一般讀者來(lái)講肯定是存在一些盲點(diǎn)的。
二糟需、先睹為快
我反復(fù)讀Doug lea的<<java并發(fā)編程實(shí)戰(zhàn)>>,卻始終有一些東西不清晰,例如:
1.CPU緩存行偽共享的問(wèn)題.拼裝指定CPU緩存行字節(jié)數(shù),來(lái)防止偽共享的問(wèn)題.
2.AQS同步器.concurrent包下的同步器基本都是有AQS來(lái)支撐的,其底層使用到了Unsafe來(lái)保證了原子性,據(jù)說(shuō)JDK9要廢棄掉這個(gè)核心成員.
3.java線(xiàn)程模型.這里就涉及到了線(xiàn)程的可見(jiàn)性洲押、內(nèi)存同步圆凰、內(nèi)存重排序和happen before。
三、再進(jìn)一步
我們也都知道IO方式有AIO驶沼、BIO争群、NIO,但是我們有沒(méi)有完全理解其真正的本質(zhì),坦然說(shuō)本人之前寫(xiě)過(guò)簡(jiǎn)易版的MVC框架來(lái)做的后臺(tái)管理系統(tǒng),其線(xiàn)程模型就是BIO,遠(yuǎn)程調(diào)用采用的是原生的RMI,很容易導(dǎo)致線(xiàn)程耗盡,性能自然也不理想换薄。我們也許都寫(xiě)過(guò)網(wǎng)絡(luò)程序,為了追求穩(wěn)定性轻要、高性能我們果斷采用Netty、MINA這種NIO框架,我們有足夠的理由放棄原生socket,但是我們能否完全理解Netty相比于原生的socket 到底給我們多做了一些什么事驹碍。我們都知道對(duì)象緩存池技術(shù),也都清楚tcp傳輸協(xié)議、長(zhǎng)連接短連接自然也不在話(huà)下,但是我們有沒(méi)有弄明白數(shù)據(jù)庫(kù)連接池是怎么復(fù)用連接的?其中tcp有沒(méi)有斷開(kāi)連接,如果沒(méi)有斷開(kāi)連接,是不是靠心跳包來(lái)維持長(zhǎng)連接?TCP頭怔球、IP頭有沒(méi)有重組?"數(shù)據(jù)庫(kù)連接"是建立在數(shù)據(jù)庫(kù)實(shí)例上的還是庫(kù)浮还、表上的,這些都值得我們?nèi)ド钏肌?最近幾年微服務(wù)盛行,底層服務(wù)都盡可能的做成服務(wù)化,但是我們是否理解RPC框架的異步、超時(shí)担汤、重試延刘、路由碘赖、負(fù)載機(jī)制,就拿dubbo異步來(lái)說(shuō),線(xiàn)程池是在客戶(hù)端創(chuàng)建還是在服務(wù)端創(chuàng)建?客戶(hù)端和服務(wù)端不在同一個(gè)jvm實(shí)例,服務(wù)端的結(jié)果怎樣通過(guò)RPC找到客戶(hù)端線(xiàn)程來(lái)完成回調(diào)的?我們都知道java是完全依賴(lài)jvm的,但是否能利用java自帶的調(diào)試工具(jps播掷、jmap撼班、jstat砰嘁、jhat等)來(lái)快速定位OOM、線(xiàn)程死鎖斟冕、頻繁GC的問(wèn)題呢磕蛇?例如這樣的問(wèn)題,比比皆是十办。
本文的目的并不是要吹噓技術(shù)的魅力,上面所說(shuō)的也不代表本人理解非常清楚,而是想談?wù)勥@幾年本人一路走來(lái)作為一名普通程序員對(duì)"程序"兩個(gè)字的理解,由于文章篇幅的問(wèn)題,我只挑了一些我認(rèn)為非常重要的點(diǎn)來(lái)講述,還請(qǐng)恕我避重就輕之責(zé)向族。本人水平也非常有限,講錯(cuò)的地方,還望大家不吝賜教,在下萬(wàn)分感謝。
前面空談了很多,該是說(shuō)些貼近實(shí)際的東西了虏等。
四霍衫、聊聊面向?qū)ο?/h3>
剛開(kāi)始接觸java的時(shí)候,"萬(wàn)物皆對(duì)象"是聽(tīng)得最多的名詞。抱著對(duì)java面向?qū)ο缶幊痰恼`解走了幾年,該是說(shuō)說(shuō)我對(duì)"對(duì)象"的理解了澄干。
??????? "誰(shuí)擁有數(shù)據(jù),誰(shuí)就提供操作數(shù)據(jù)的方法" ,這句話(huà)我覺(jué)得對(duì)我理解什么是面向?qū)ο笃鹆撕艽笞饔敏锓R驗(yàn)殡S著工作時(shí)間越來(lái)越久,看過(guò)的開(kāi)源項(xiàng)目越來(lái)越多,越發(fā)容易理解面向?qū)ο蟮暮锰幜司宓选G岸螘r(shí)間公司分享Quartz,所以了解了一下,絕對(duì)是面向?qū)ο蟮木?定時(shí)任務(wù)本來(lái)是一個(gè)業(yè)界不能缺失的重要組件,Quartz實(shí)現(xiàn)了對(duì)業(yè)界比較統(tǒng)一的定時(shí)調(diào)度模型進(jìn)行封裝,抽取出了Scheduler患整、Trigger、Job紧憾、JobDetail四個(gè)對(duì)象,代碼實(shí)現(xiàn)并不是本章的重點(diǎn),而且個(gè)人認(rèn)為框架中的代碼并不是阻擋我們理解的瓶頸所在,而是它的設(shè)計(jì)方式,模型抽象赴穗。話(huà)說(shuō)回來(lái),Quartz中的每個(gè)對(duì)象只做自己應(yīng)該做的事,調(diào)度器總不應(yīng)該處理時(shí)間觸發(fā)器吧?因?yàn)檎{(diào)度器更擅長(zhǎng)處理任務(wù)調(diào)度,對(duì)其他東西都不關(guān)心,專(zhuān)心做好自己的事就已經(jīng)足夠了般眉。
???????<<重構(gòu)>>一書(shū)中有講到重構(gòu)的最終結(jié)果就是設(shè)計(jì)模式,所以說(shuō)我們應(yīng)該不斷重構(gòu),不斷使自己的對(duì)象更加職責(zé)單一化,方法簡(jiǎn)單化,最大程度上滿(mǎn)足代碼可復(fù)用潜支。雖然說(shuō)單一職責(zé)毁腿、里氏替換苛茂、對(duì)擴(kuò)展開(kāi)放對(duì)修改關(guān)閉這些基本原則和23個(gè)設(shè)計(jì)模式我們都很熟悉,但是要想編寫(xiě)出完全面向?qū)ο蟮某绦蚱鋵?shí)還是有難度的妓羊。尤其是每天在被各種業(yè)務(wù)代碼沖擊的情況下,能保證功能順利上線(xiàn)就已倍感欣慰了,還跟我談什么面向?qū)ο蟆K哉f(shuō)偶爾在同事的代碼中看到一個(gè)模板方法模式會(huì)讓我驚嘆不已,看到一個(gè)策略模式來(lái)替換掉復(fù)雜的ifelse或者swich語(yǔ)句更會(huì)讓我拍手稱(chēng)奇裕循。如果還用到了責(zé)任鏈或者復(fù)合之類(lèi)的設(shè)計(jì)模式,我只會(huì)感嘆一句:"小伙子,你肯定工作又不飽和了吧!還有心思設(shè)計(jì)這個(gè)剥哑!" 當(dāng)然這只是玩笑話(huà),心里還是非常認(rèn)同并且敬佩的.
五株婴、聊聊設(shè)計(jì)模式
下面說(shuō)幾個(gè)我常用的設(shè)計(jì)模式,總結(jié)下自己的看法。
1.單例模式
???????單例模式一般用在整個(gè)應(yīng)用內(nèi)只有一份的情況下大审。像數(shù)據(jù)庫(kù)連接池這種比較昂貴的資源就可以使用單例來(lái)維護(hù)座哩。像Dubbo中的ExtensionLoader也是一種單例模式的實(shí)現(xiàn),在啟動(dòng)的時(shí)候就已經(jīng)將配置文件全部加載,當(dāng)要用的時(shí)候 直接從內(nèi)存取根穷。單例模式一般有惡漢、懶漢溶浴、靜態(tài)內(nèi)部類(lèi)方式,也有用枚舉來(lái)實(shí)現(xiàn)單例的做法,但實(shí)際中很少遇到士败。
2.工廠(chǎng)模式
???????工廠(chǎng)模式分為工廠(chǎng)方法褥伴、抽象工廠(chǎng)重慢、靜態(tài)工廠(chǎng)這么幾類(lèi)(可能有不同叫法).其主要目的還是為了解耦,當(dāng)我們需要添加新對(duì)象的時(shí)候,不需要修改客戶(hù)端代碼,即對(duì)調(diào)用方無(wú)感知。Spring就是一個(gè)巨大的工廠(chǎng),你可以從你的spring容器里隨意獲取你想要的東西隅熙。比如說(shuō)我現(xiàn)在需要向客戶(hù)端暴露一個(gè)方法,客戶(hù)端只需傳入不同的參數(shù)就可以獲取不同的對(duì)象,我認(rèn)為這就是一個(gè)簡(jiǎn)單工廠(chǎng)的實(shí)現(xiàn)。做數(shù)據(jù)路由的時(shí)候,我們可以根據(jù)不同的網(wǎng)絡(luò)環(huán)境或者配置等等其他外來(lái)因素來(lái)匹配不同的對(duì)象,這里我覺(jué)得做成抽象工廠(chǎng)就比較合適,因?yàn)樗梢跃哂卸鄠€(gè)行為,比其他工廠(chǎng)"善變"一點(diǎn)核芽。
3.適配器模式
???????適配器無(wú)處不在囚戚。寫(xiě)swing程序的時(shí)候,為了實(shí)現(xiàn)某個(gè)事件接口需要重寫(xiě)很多個(gè)方法,那可想可知是非常痛苦的,代碼層面也很不美觀,所以就有了xxAdapter,這其實(shí)就是一個(gè)適配類(lèi).我們經(jīng)常用的List、Collection也提供了骨架類(lèi)AbstractList,AbstractCollection轧简,當(dāng)我們需要擴(kuò)展自己的List的時(shí)候只需要繼承AbstractList即可,個(gè)人認(rèn)為這也是一種適配器實(shí)現(xiàn)驰坊。像ArrayList中的listIterator也是一種適配器實(shí)現(xiàn)等等。適配器模式,我認(rèn)為就是這個(gè)類(lèi)不具備某個(gè)能力,但是要擴(kuò)展其行為的一種手段哮独。像cygwin拳芙、vmware可以認(rèn)為是一種基于操作系統(tǒng)的適配,teamviewer也可以當(dāng)成一種基于終端的適配察藐。
5.觀察者模式
???????觀察者模式就是一種發(fā)布訂閱模式,和MQ其實(shí)一樣,只是MQ是一種跨進(jìn)程的實(shí)現(xiàn)。MQ比較適合大容量分飞、更可靠、更加復(fù)雜的異構(gòu)系統(tǒng)浆竭。例如N個(gè)客戶(hù)端訂閱自己關(guān)心的事件,當(dāng)事件到達(dá)時(shí),客戶(hù)端就可以收到通知,而不用在觸發(fā)事件的地方不斷添加訂閱者浸须。例如登錄注冊(cè)送獎(jiǎng)勵(lì)、發(fā)短信,我覺(jué)得都可以用發(fā)布訂閱的方式來(lái)做邦泄。比如要在登錄成功后送積分,只需要新建一個(gè)送積分的服務(wù)去訂閱登錄消息即可(這里就不討論丟消息或者重復(fù)消息的情況)删窒。guava中的EventBus就是一種比較好的發(fā)布訂閱的實(shí)現(xiàn).
由于文章篇幅問(wèn)題,其他就省略不講了。
???????總之,本人在遇到多個(gè)參數(shù)的構(gòu)造函數(shù)時(shí),總會(huì)想到使用建造者模式來(lái)做到鏈?zhǔn)秸{(diào)用,會(huì)考慮使用策略模式替換掉復(fù)雜的判斷語(yǔ)句和switch語(yǔ)句,針對(duì)只有少量不同行為的對(duì)象,會(huì)考慮使用模板方法讓子類(lèi)進(jìn)行自定義的覆蓋顺囊。當(dāng)在做類(lèi)似于MOCK肌索、類(lèi)AOP操作的時(shí)候,會(huì)使用代理和工廠(chǎng)。如果做接口的過(guò)渡或者對(duì)某些客戶(hù)端隱藏一些特定的行為,我會(huì)考慮使用適配器特碳。一些全局的資源分配,會(huì)考慮使用單例模式诚亚。對(duì)象的包裝和增強(qiáng)我會(huì)考慮使用復(fù)合和裝飾者,如果做一些監(jiān)聽(tīng)事件的解耦,我會(huì)考慮使用觀察者等等。設(shè)計(jì)模式我覺(jué)得只是一種指導(dǎo),具體怎么做還是由自己來(lái)掌握午乓、怎么樣做得更容易被理解站宗、更容易被復(fù)用,我認(rèn)為這就是設(shè)計(jì)模式。最后還想強(qiáng)調(diào)一句名言: 我們應(yīng)該不斷重構(gòu),重構(gòu)的最終結(jié)果就是設(shè)計(jì)模式~
六益愈、下節(jié)預(yù)覽
1.為什么不叫java并行編程而是并發(fā)編程梢灭?
2.單核CPU 多線(xiàn)程的好處?
3.重排序
4.volatie、synchronized
5.重入鎖蒸其、讀寫(xiě)鎖敏释、分布式鎖
6.線(xiàn)程池
7.阻塞隊(duì)列
8.happen before
9.CAS
10.幾個(gè)重點(diǎn)類(lèi)的源碼剖析(阻塞隊(duì)列、信號(hào)量摸袁、CountDownLatch钥顽、AQS)
11.Master worker、Fork join
談?wù)勎覍?duì)java的理解一文篇幅較大,由于時(shí)間不是很充分,我準(zhǔn)備分章節(jié)來(lái)講靠汁。大體分為下面幾個(gè)章節(jié)
二蜂大、對(duì)并發(fā)編程理解
三、對(duì)開(kāi)源的幾點(diǎn)理解
四蝶怔、對(duì)jvm的看法
五县爬、對(duì)分布式系統(tǒng)的幾點(diǎn)認(rèn)識(shí)