摘要: 世界邦旅行網(wǎng)創(chuàng)業(yè)團(tuán)隊(北京)招聘Java工程師/PHP工程師/測試工程師/前端工程師/移動開發(fā)工程師等 閱讀全文
2010年6月21日 #
摘要: Bash 為了提高命令的解析速度,將解析過的命令的全路徑保存在hash表中,因此下次執(zhí)行的時候就無需進(jìn)行再次解析。如果在shell中修改了已經(jīng)緩存過的命令路徑,那么bash可能不能立即生效。這樣就會發(fā)生命令不能解析或者文件不存在的問題,盡管可執(zhí)行文件確實存在。 閱讀全文
摘要: OS X 下批量轉(zhuǎn)換圖片格式。 閱讀全文
摘要: Google的web字體在我朝訪問巨慢,尤其是HTTPS方式更慢,本文幫助大家解決octopress默認(rèn)的google web字體訪問太慢的問題。 閱讀全文
摘要: JRebel最新版本6.0.0的下載地址及個人學(xué)習(xí)使用版本。 閱讀全文
摘要: 本文描述如何申請2.5$每年的SSL證書,并啟用Nginx的HTTPS訪問。 閱讀全文
摘要: 線程池
并發(fā)最常見用于線程池,顯然使用線程池可以有效的提高吞吐量。
最常見、比較復(fù)雜一個場景是Web容器的線程池。Web容器使用線程池同步或者異步處理HTTP請求,同時這也可以有效的復(fù)用HTTP連接,降低資源申請的開銷。通常我們認(rèn)為HTTP請求時非常昂貴的,并且也是比較耗費資源和性能的,所以線程池在這里就扮演了非常重要的角色。
在線程池的章節(jié)中非常詳細(xì)的討論了線程池的原理和使用,同時也提到了,線程池的配置和參數(shù)對性能的影響是巨大的。不盡如此,受限于資源(機(jī)器的性能、網(wǎng)絡(luò)的帶寬等等)、依賴的服務(wù),客戶端的響應(yīng)速度等,線程池的威力也不會一直增長。達(dá)到了線程池的瓶頸后,性能和吞吐量都會大幅度降低。
一直增加機(jī)器的性能或者增大線程的個數(shù),并不一定能有效的提高吞吐量。高并發(fā)的情況下,機(jī)器的負(fù)載會大幅提升,這時候機(jī)器的穩(wěn)定性、服務(wù)的可靠性都會下降。
盡管如此,線程池依然是提高吞吐量的一個有效措施,配合合適的參數(shù)能夠有效的充分利用資源,提高資源的利用率。 閱讀全文
并發(fā)最常見用于線程池,顯然使用線程池可以有效的提高吞吐量。
最常見、比較復(fù)雜一個場景是Web容器的線程池。Web容器使用線程池同步或者異步處理HTTP請求,同時這也可以有效的復(fù)用HTTP連接,降低資源申請的開銷。通常我們認(rèn)為HTTP請求時非常昂貴的,并且也是比較耗費資源和性能的,所以線程池在這里就扮演了非常重要的角色。
在線程池的章節(jié)中非常詳細(xì)的討論了線程池的原理和使用,同時也提到了,線程池的配置和參數(shù)對性能的影響是巨大的。不盡如此,受限于資源(機(jī)器的性能、網(wǎng)絡(luò)的帶寬等等)、依賴的服務(wù),客戶端的響應(yīng)速度等,線程池的威力也不會一直增長。達(dá)到了線程池的瓶頸后,性能和吞吐量都會大幅度降低。
一直增加機(jī)器的性能或者增大線程的個數(shù),并不一定能有效的提高吞吐量。高并發(fā)的情況下,機(jī)器的負(fù)載會大幅提升,這時候機(jī)器的穩(wěn)定性、服務(wù)的可靠性都會下降。
盡管如此,線程池依然是提高吞吐量的一個有效措施,配合合適的參數(shù)能夠有效的充分利用資源,提高資源的利用率。 閱讀全文
摘要: 死鎖與活躍度
前面談了很多并發(fā)的特性和工具,但是大部分都是和鎖有關(guān)的。我們使用鎖來保證線程安全,但是這也會引起一些問題。
鎖順序死鎖(lock-ordering deadlock):多個線程試圖通過不同的順序獲得多個相同的資源,則發(fā)生的循環(huán)鎖依賴現(xiàn)象。
動態(tài)的鎖順序死鎖(Dynamic Lock Order Deadlocks):多個線程通過傳遞不同的鎖造成的鎖順序死鎖問題。
資源死鎖(Resource Deadlocks):線程間相互等待對方持有的鎖,并且誰都不會釋放自己持有的鎖發(fā)生的死鎖。也就是說當(dāng)現(xiàn)場持有和等待的目標(biāo)成為資源,就有可能發(fā)生此死鎖。這和鎖順序死鎖不一樣的地方是,競爭的資源之間并沒有嚴(yán)格先后順序,僅僅是相互依賴而已。 閱讀全文
前面談了很多并發(fā)的特性和工具,但是大部分都是和鎖有關(guān)的。我們使用鎖來保證線程安全,但是這也會引起一些問題。
鎖順序死鎖(lock-ordering deadlock):多個線程試圖通過不同的順序獲得多個相同的資源,則發(fā)生的循環(huán)鎖依賴現(xiàn)象。
動態(tài)的鎖順序死鎖(Dynamic Lock Order Deadlocks):多個線程通過傳遞不同的鎖造成的鎖順序死鎖問題。
資源死鎖(Resource Deadlocks):線程間相互等待對方持有的鎖,并且誰都不會釋放自己持有的鎖發(fā)生的死鎖。也就是說當(dāng)現(xiàn)場持有和等待的目標(biāo)成為資源,就有可能發(fā)生此死鎖。這和鎖順序死鎖不一樣的地方是,競爭的資源之間并沒有嚴(yán)格先后順序,僅僅是相互依賴而已。 閱讀全文
摘要: 剛看到這個月的編程語言排行榜,很顯然java的霸主地位很快就會在發(fā)達(dá)國家被擠掉,C語言依然是王者(想想上個月自己買的兩個C語言的書,冷汗直流)。看來我遲早要回歸C,這才是真正的王道。
非常令人吃驚的是C++語言依然不夠堅挺,由于Windows 7/Windows 8的發(fā)力,C#很快就會搶占C++的市場,估計很快就會將C++從前三名中擠下去。
iPhone/iPad的熱銷讓Object C繼續(xù)火熱,前十的位置還是可以持續(xù)很久的,這一點毋庸置疑。移動設(shè)備開發(fā)的高端人才現(xiàn)在是高薪難求,如果有時間我也要繼續(xù)關(guān)注下。 閱讀全文
非常令人吃驚的是C++語言依然不夠堅挺,由于Windows 7/Windows 8的發(fā)力,C#很快就會搶占C++的市場,估計很快就會將C++從前三名中擠下去。
iPhone/iPad的熱銷讓Object C繼續(xù)火熱,前十的位置還是可以持續(xù)很久的,這一點毋庸置疑。移動設(shè)備開發(fā)的高端人才現(xiàn)在是高薪難求,如果有時間我也要繼續(xù)關(guān)注下。 閱讀全文
摘要: Zookeeper客戶端和服務(wù)端維持一個長連接,每隔10s向服務(wù)端發(fā)送一個心跳,服務(wù)端返回客戶端一個響應(yīng)。這就是一個Session連接,擁有全局唯一的session id。Session連接通常是一直有效,如果因為網(wǎng)絡(luò)原因斷開了連接,客戶端會使用相同的session id進(jìn)行重連。由于服務(wù)端保留了session的各種狀態(tài),尤其是各種瞬時節(jié)點是否刪除依賴于session是否失效。
Session失效問題
通常客戶端主動關(guān)閉連接認(rèn)為是一次session失效。另外也有可能因為其它未知原因,例如網(wǎng)絡(luò)超時導(dǎo)致的session失效問題。在服務(wù)端看來,無法區(qū)分session失效是何種情況,一次一旦發(fā)生session失效,一定時間后就會將session持有的所有watcher以及瞬時節(jié)點刪除。
而對于Zookeeper客戶端而言,一旦發(fā)生失效不知道是否該重連,這涉及到watcher和瞬時節(jié)點問題,因此Zookeeper客戶端認(rèn)為,一旦發(fā)生了seesion失效,那么就認(rèn)為客戶端死掉了。從而所有操作都不能夠進(jìn)行。參考 How should I handle SESSION 閱讀全文
Session失效問題
通常客戶端主動關(guān)閉連接認(rèn)為是一次session失效。另外也有可能因為其它未知原因,例如網(wǎng)絡(luò)超時導(dǎo)致的session失效問題。在服務(wù)端看來,無法區(qū)分session失效是何種情況,一次一旦發(fā)生session失效,一定時間后就會將session持有的所有watcher以及瞬時節(jié)點刪除。
而對于Zookeeper客戶端而言,一旦發(fā)生失效不知道是否該重連,這涉及到watcher和瞬時節(jié)點問題,因此Zookeeper客戶端認(rèn)為,一旦發(fā)生了seesion失效,那么就認(rèn)為客戶端死掉了。從而所有操作都不能夠進(jìn)行。參考 How should I handle SESSION 閱讀全文
摘要: 為了提高性能,最近將Redis從2.2.x的最新版2.2.12升級到2.4.x(2.4.2),驚喜的發(fā)現(xiàn)內(nèi)存占用節(jié)省了很多。大贊!
有人說Redis的作者是一個勤奮的人,深表同意!
本來升級是為了增加批量操作從而提高性能,沒想到內(nèi)存占用節(jié)省了很多。
對于32位的操作系統(tǒng)而言,節(jié)省內(nèi)存62%,對于64位操作系統(tǒng)而言節(jié)省73%。非常可觀。 閱讀全文
有人說Redis的作者是一個勤奮的人,深表同意!
本來升級是為了增加批量操作從而提高性能,沒想到內(nèi)存占用節(jié)省了很多。
對于32位的操作系統(tǒng)而言,節(jié)省內(nèi)存62%,對于64位操作系統(tǒng)而言節(jié)省73%。非常可觀。 閱讀全文
摘要: 當(dāng)Ajax遇到GBK/GB2312,我們恨不能將所有項目的編碼統(tǒng)一改為UTF-8。顯然這個做法,成本太高了。下面給出了一個完善的解決方案。此方案不僅僅限于Ajax提交數(shù)據(jù),也適用于普通訪問請求。 閱讀全文
摘要: 本節(jié)中將探討線程池是如何處理任務(wù)結(jié)果以及延遲、周期性任務(wù)調(diào)度是如何實現(xiàn)的。
結(jié)合上節(jié)線程池的原理和實現(xiàn),徹底分析了線程池對任務(wù)的結(jié)果處理,尤其是對延遲、周期性任務(wù)是如何執(zhí)行的。
這也是并發(fā)系列中源碼分析的最后一小節(jié)。 閱讀全文
結(jié)合上節(jié)線程池的原理和實現(xiàn),徹底分析了線程池對任務(wù)的結(jié)果處理,尤其是對延遲、周期性任務(wù)是如何執(zhí)行的。
這也是并發(fā)系列中源碼分析的最后一小節(jié)。 閱讀全文
摘要: 這一節(jié)中我們將詳細(xì)討論線程池是如何執(zhí)行一個任務(wù)的,尤其是如何處理線程池的大小、核心大小、最大大小、任務(wù)隊列等之間的關(guān)系的。 閱讀全文
摘要: 我們根據(jù)線程池的要求也很能夠猜測出其數(shù)據(jù)結(jié)構(gòu)出來。
線程池需要支持多個線程并發(fā)執(zhí)行,因此有一個線程集合Collection來執(zhí)行線程任務(wù);
涉及任務(wù)的異步執(zhí)行,因此需要有一個集合來緩存任務(wù)隊列Collection;
很顯然在多個線程之間協(xié)調(diào)多個任務(wù),那么就需要一個線程安全的任務(wù)集合,同時還需要支持阻塞、超時操作,那么BlockingQueue是必不可少的;
既然是線程池,出發(fā)點就是提高系統(tǒng)性能同時降低資源消耗,那么線程池的大小就有限制,因此需要有一個核心線程池大小(線程個數(shù))和一個最大線程池大小(線程個數(shù)),有一個計數(shù)用來描述當(dāng)前線程池大小;
如果是有限的線程池大小,那么長時間不使用的線程資源就應(yīng)該銷毀掉,這樣就需要一個線程空閑時間的計數(shù)來描述線程何時被銷毀;
前面描述過線程池也是有生命周期的,因此需要有一個狀態(tài)來描述線程池當(dāng)前的運行狀態(tài);
線程池的任務(wù)隊列如果有邊界,那么就需要有一個任務(wù)拒絕策略來處理過多的任務(wù),同時在線程池的銷毀階段也需要有一個任務(wù)拒絕策略來處理新加入的任務(wù);
上面種 閱讀全文
線程池需要支持多個線程并發(fā)執(zhí)行,因此有一個線程集合Collection
涉及任務(wù)的異步執(zhí)行,因此需要有一個集合來緩存任務(wù)隊列Collection
很顯然在多個線程之間協(xié)調(diào)多個任務(wù),那么就需要一個線程安全的任務(wù)集合,同時還需要支持阻塞、超時操作,那么BlockingQueue是必不可少的;
既然是線程池,出發(fā)點就是提高系統(tǒng)性能同時降低資源消耗,那么線程池的大小就有限制,因此需要有一個核心線程池大小(線程個數(shù))和一個最大線程池大小(線程個數(shù)),有一個計數(shù)用來描述當(dāng)前線程池大小;
如果是有限的線程池大小,那么長時間不使用的線程資源就應(yīng)該銷毀掉,這樣就需要一個線程空閑時間的計數(shù)來描述線程何時被銷毀;
前面描述過線程池也是有生命周期的,因此需要有一個狀態(tài)來描述線程池當(dāng)前的運行狀態(tài);
線程池的任務(wù)隊列如果有邊界,那么就需要有一個任務(wù)拒絕策略來處理過多的任務(wù),同時在線程池的銷毀階段也需要有一個任務(wù)拒絕策略來處理新加入的任務(wù);
上面種 閱讀全文
摘要: 在JDK 5.0之前,java.util.Timer/TimerTask是唯一的內(nèi)置任務(wù)調(diào)度方法,而且在很長一段時間里很熱衷于使用這種方式進(jìn)行周期性任務(wù)調(diào)度。
首先研究下Timer/TimerTask的特性(至于javax.swing.Timer就不再研究了)。
上面三段代碼反映了Timer/TimerTask的以下特性:
Timer對任務(wù)的調(diào)度是基于絕對時間的。
所有的TimerTask只有一個線程TimerThread來執(zhí)行,因此同一時刻只有一個TimerTask在執(zhí)行。
任何一個TimerTask的執(zhí)行異常都會導(dǎo)致Timer終止所有任務(wù)。
由于基于絕對時間并且是單線程執(zhí)行,因此在多個任務(wù)調(diào)度時,長時間執(zhí)行的任務(wù)被執(zhí)行后有可能導(dǎo)致短時間任務(wù)快速在短時間內(nèi)被執(zhí)行多次或者干脆丟棄多個任務(wù)。 閱讀全文
首先研究下Timer/TimerTask的特性(至于javax.swing.Timer就不再研究了)。
上面三段代碼反映了Timer/TimerTask的以下特性:
Timer對任務(wù)的調(diào)度是基于絕對時間的。
所有的TimerTask只有一個線程TimerThread來執(zhí)行,因此同一時刻只有一個TimerTask在執(zhí)行。
任何一個TimerTask的執(zhí)行異常都會導(dǎo)致Timer終止所有任務(wù)。
由于基于絕對時間并且是單線程執(zhí)行,因此在多個任務(wù)調(diào)度時,長時間執(zhí)行的任務(wù)被執(zhí)行后有可能導(dǎo)致短時間任務(wù)快速在短時間內(nèi)被執(zhí)行多次或者干脆丟棄多個任務(wù)。 閱讀全文
摘要: 上一節(jié)中提到關(guān)閉線程池過程中需要對新提交的任務(wù)進(jìn)行處理。這個是java.util.concurrent.RejectedExecutionHandler處理的邏輯。
在沒有分析線程池原理之前先來分析下為什么有任務(wù)拒絕的情況發(fā)生。
這里先假設(shè)一個前提:線程池有一個任務(wù)隊列,用于緩存所有待處理的任務(wù),正在處理的任務(wù)將從任務(wù)隊列中移除。因此在任務(wù)隊列長度有限的情況下就會出現(xiàn)新任務(wù)的拒絕處理問題,需要有一種策略來處理應(yīng)該加入任務(wù)隊列卻因為隊列已滿無法加入的情況。另外在線程池關(guān)閉的時候也需要對任務(wù)加入隊列操作進(jìn)行額外的協(xié)調(diào)處理。
RejectedExecutionHandler提供了四種方式來處理任務(wù)拒絕策略。 閱讀全文
在沒有分析線程池原理之前先來分析下為什么有任務(wù)拒絕的情況發(fā)生。
這里先假設(shè)一個前提:線程池有一個任務(wù)隊列,用于緩存所有待處理的任務(wù),正在處理的任務(wù)將從任務(wù)隊列中移除。因此在任務(wù)隊列長度有限的情況下就會出現(xiàn)新任務(wù)的拒絕處理問題,需要有一種策略來處理應(yīng)該加入任務(wù)隊列卻因為隊列已滿無法加入的情況。另外在線程池關(guān)閉的時候也需要對任務(wù)加入隊列操作進(jìn)行額外的協(xié)調(diào)處理。
RejectedExecutionHandler提供了四種方式來處理任務(wù)拒絕策略。 閱讀全文
摘要: 本著開發(fā)的原則,既然用到了別人家的東西,所以決定公開出來,也算是給別人一個參考。 閱讀全文
摘要:
我們知道線程是有多種執(zhí)行狀態(tài)的,同樣管理線程的線程池也有多種狀態(tài)。JVM會在所有線程(非后臺daemon線程)全部終止后才退出,為了節(jié)省資源和有效釋放資源關(guān)閉一個線程池就顯得很重要。有時候無法正確的關(guān)閉線程池,將會阻止JVM的結(jié)束。
線程池Executor是異步的執(zhí)行任務(wù),因此任何時刻不能夠直接獲取提交的任務(wù)的狀態(tài)。這些任務(wù)有可能已經(jīng)完成,也有可能正在執(zhí)行或者還在排隊等待執(zhí)行。因此關(guān)閉線程池可能出現(xiàn)一下幾種情況:
平緩關(guān)閉:已經(jīng)啟動的任務(wù)全部執(zhí)行完畢,同時不再接受新的任務(wù)
立即關(guān)閉:取消所有正在執(zhí)行和未執(zhí)行的任務(wù)
另外關(guān)閉線程池后對于任務(wù)的狀態(tài)應(yīng)該有相應(yīng)的反饋信息。 閱讀全文
我們知道線程是有多種執(zhí)行狀態(tài)的,同樣管理線程的線程池也有多種狀態(tài)。JVM會在所有線程(非后臺daemon線程)全部終止后才退出,為了節(jié)省資源和有效釋放資源關(guān)閉一個線程池就顯得很重要。有時候無法正確的關(guān)閉線程池,將會阻止JVM的結(jié)束。
線程池Executor是異步的執(zhí)行任務(wù),因此任何時刻不能夠直接獲取提交的任務(wù)的狀態(tài)。這些任務(wù)有可能已經(jīng)完成,也有可能正在執(zhí)行或者還在排隊等待執(zhí)行。因此關(guān)閉線程池可能出現(xiàn)一下幾種情況:
平緩關(guān)閉:已經(jīng)啟動的任務(wù)全部執(zhí)行完畢,同時不再接受新的任務(wù)
立即關(guān)閉:取消所有正在執(zhí)行和未執(zhí)行的任務(wù)
另外關(guān)閉線程池后對于任務(wù)的狀態(tài)應(yīng)該有相應(yīng)的反饋信息。 閱讀全文
摘要: Java里面線程池的頂級接口是Executor,但是嚴(yán)格意義上講Executor并不是一個線程池,而只是一個執(zhí)行線程的工具。真正的線程池接口是ExecutorService。
下面這張圖完整描述了線程池的類體系結(jié)構(gòu)。 閱讀全文
下面這張圖完整描述了線程池的類體系結(jié)構(gòu)。 閱讀全文
摘要: 從這一節(jié)開始正式進(jìn)入線程池的部分。其實整個體系已經(jīng)拖了很長的時間,因此后面的章節(jié)會加快速度,甚至只是一個半成品或者簡單化,以后有時間的慢慢補充、完善。
其實線程池是并發(fā)包里面很重要的一部分,在實際情況中也是使用很多的一個重要組件。
下圖描述的是線程池API的一部分。廣義上的完整線程池可能還包括Thread/Runnable、Timer/TimerTask等部分。這里只介紹主要的和高級的API以及架構(gòu)和原理。 閱讀全文
其實線程池是并發(fā)包里面很重要的一部分,在實際情況中也是使用很多的一個重要組件。
下圖描述的是線程池API的一部分。廣義上的完整線程池可能還包括Thread/Runnable、Timer/TimerTask等部分。這里只介紹主要的和高級的API以及架構(gòu)和原理。 閱讀全文
摘要: 最近的項目使用的是舊的ibatis2.x版本,有時候為了方便調(diào)試,想輸出SQL執(zhí)行的語句和參數(shù)。我記得應(yīng)該有某些logger的日志級別修改為DEBUG就可以看到。當(dāng)然為了方便可以直接在log4j(如果使用log4j的話)的root日志級別修改為DEBUG,并且輸出appender的接受級別修改為DEBUG就可以了。這樣是可以看到日志信息(SQL/參數(shù))等,但是同時也輸出了過多的其它logger信息,顯然在一個稍微大一點的系統(tǒng)里面debug的信息應(yīng)該都是非常多的,不說別的,光是spring的日志就夠好多頁了。
為了解決過多的日志,翻出ibatis源碼,看了下。ibatis的執(zhí)行流程大致是這樣的。 閱讀全文
為了解決過多的日志,翻出ibatis源碼,看了下。ibatis的執(zhí)行流程大致是這樣的。 閱讀全文
摘要: 本小節(jié)是《并發(fā)容器》的最后一部分,這一個小節(jié)描述的是針對List/Set接口的一個線程版本。
在《并發(fā)隊列與Queue簡介》中介紹了并發(fā)容器的一個概括,主要描述的是Queue的實現(xiàn)。其中特別提到一點LinkedList是List/Queue的實現(xiàn),但是LinkedList確實非線程安全的。不管BlockingQueue還是ConcurrentMap的實現(xiàn),我們發(fā)現(xiàn)都是針對鏈表的實現(xiàn),當(dāng)然盡可能的使用CAS或者Lock的特性,同時都有通過鎖部分容器來提供并發(fā)的特性。而對于List或者Set而言,增、刪操作其實都是針對整個容器,因此每次操作都不可避免的需要鎖定整個容器空間,性能肯定會大打折扣。要實現(xiàn)一個線程安全的List/Set,只需要在修改操作的時候進(jìn)行同步即可,比如使用java.util.Collections.synchronizedList(List)或者java.util.Collections.synchronizedSet(Set)。當(dāng)然也可以使用Lock來實現(xiàn)線程安全的List/Set。
通常情況下我們的高并發(fā)都發(fā)生在“多讀少寫”的情況,因此如果 閱讀全文
在《并發(fā)隊列與Queue簡介》中介紹了并發(fā)容器的一個概括,主要描述的是Queue的實現(xiàn)。其中特別提到一點LinkedList是List/Queue的實現(xiàn),但是LinkedList確實非線程安全的。不管BlockingQueue還是ConcurrentMap的實現(xiàn),我們發(fā)現(xiàn)都是針對鏈表的實現(xiàn),當(dāng)然盡可能的使用CAS或者Lock的特性,同時都有通過鎖部分容器來提供并發(fā)的特性。而對于List或者Set而言,增、刪操作其實都是針對整個容器,因此每次操作都不可避免的需要鎖定整個容器空間,性能肯定會大打折扣。要實現(xiàn)一個線程安全的List/Set,只需要在修改操作的時候進(jìn)行同步即可,比如使用java.util.Collections.synchronizedList(List
通常情況下我們的高并發(fā)都發(fā)生在“多讀少寫”的情況,因此如果 閱讀全文
摘要: 可以在對中對元素進(jìn)行配對和交換的線程的同步點。每個線程將條目上的某個方法呈現(xiàn)給 exchange 方法,與伙伴線程進(jìn)行匹配,并且在返回時接收其伙伴的對象。Exchanger 可能被視為 SynchronousQueue 的雙向形式。
換句話說Exchanger提供的是一個交換服務(wù),允許原子性的交換兩個(多個)對象,但同時只有一對才會成功。先看一個簡單的實例模型。 閱讀全文
換句話說Exchanger提供的是一個交換服務(wù),允許原子性的交換兩個(多個)對象,但同時只有一對才會成功。先看一個簡單的實例模型。 閱讀全文
摘要: 這個小節(jié)介紹Queue的最后一個工具,也是最強大的一個工具。從名稱上就可以看到此工具的特點:雙向并發(fā)阻塞隊列。所謂雙向是指可以從隊列的頭和尾同時操作,并發(fā)只是線程安全的實現(xiàn),阻塞允許在入隊出隊不滿足條件時掛起線程,這里說的隊列是指支持FIFO/FILO實現(xiàn)的鏈表。
首先看下LinkedBlockingDeque的數(shù)據(jù)結(jié)構(gòu)。通常情況下從數(shù)據(jù)結(jié)構(gòu)上就能看出這種實現(xiàn)的優(yōu)缺點,這樣就知道如何更好的使用工具了。 閱讀全文
首先看下LinkedBlockingDeque的數(shù)據(jù)結(jié)構(gòu)。通常情況下從數(shù)據(jù)結(jié)構(gòu)上就能看出這種實現(xiàn)的優(yōu)缺點,這樣就知道如何更好的使用工具了。 閱讀全文
摘要:
有一段時間沒有更新了。接著上節(jié)繼續(xù)吧。
Queue除了前面介紹的實現(xiàn)外,還有一種雙向的Queue實現(xiàn)Deque。這種隊列允許在隊列頭和尾部進(jìn)行入隊出隊操作,因此在功能上比Queue顯然要更復(fù)雜。下圖描述的是Deque的完整體系圖。需要說明的是LinkedList也已經(jīng)加入了Deque的一部分(LinkedList是從jdk1.2 開始就存在數(shù)據(jù)結(jié)構(gòu))。 閱讀全文
有一段時間沒有更新了。接著上節(jié)繼續(xù)吧。
Queue除了前面介紹的實現(xiàn)外,還有一種雙向的Queue實現(xiàn)Deque。這種隊列允許在隊列頭和尾部進(jìn)行入隊出隊操作,因此在功能上比Queue顯然要更復(fù)雜。下圖描述的是Deque的完整體系圖。需要說明的是LinkedList也已經(jīng)加入了Deque的一部分(LinkedList是從jdk1.2 開始就存在數(shù)據(jù)結(jié)構(gòu))。 閱讀全文
摘要:
在Set中有一個排序的集合SortedSet,用來保存按照自然順序排列的對象。Queue中同樣引入了一個支持排序的FIFO模型。
并發(fā)隊列與Queue簡介 中介紹了,PriorityQueue和PriorityBlockingQueue就是支持排序的Queue。顯然一個支持阻塞的排序Queue要比一個非線程安全的Queue實現(xiàn)起來要復(fù)雜的多,因此下面只介紹PriorityBlockingQueue,至于PriorityQueue只需要去掉Blocking功能就基本相同了。 閱讀全文
在Set中有一個排序的集合SortedSet,用來保存按照自然順序排列的對象。Queue中同樣引入了一個支持排序的FIFO模型。
并發(fā)隊列與Queue簡介 中介紹了,PriorityQueue和PriorityBlockingQueue就是支持排序的Queue。顯然一個支持阻塞的排序Queue要比一個非線程安全的Queue實現(xiàn)起來要復(fù)雜的多,因此下面只介紹PriorityBlockingQueue,至于PriorityQueue只需要去掉Blocking功能就基本相同了。 閱讀全文
摘要: 在上一節(jié)中詳細(xì)分析了LinkedBlockingQueue 的實現(xiàn)原理。實現(xiàn)一個可擴(kuò)展的隊列通常有兩種方式:一種方式就像LinkedBlockingQueue一樣使用鏈表,也就是每一個元素帶有下一個元素的引用,這樣的隊列原生就是可擴(kuò)展的;另外一種就是通過數(shù)組實現(xiàn),一旦隊列的大小達(dá)到數(shù)組的容量的時候就將數(shù)組擴(kuò)充一倍(或者一定的系數(shù)倍),從而達(dá)到擴(kuò)容的目的。常見的ArrayList就屬于第二種。前面章節(jié)介紹過的HashMap確是綜合使用了這兩種方式。
對于一個Queue而言,同樣可以使用數(shù)組實現(xiàn)。使用數(shù)組的好處在于各個元素之間原生就是通過數(shù)組的索引關(guān)聯(lián)起來的,一次元素之間就是有序的,在通過索引操作數(shù)組就方便多了。當(dāng)然也有它不利的一面,擴(kuò)容起來比較麻煩,同時刪除一個元素也比較低效。
ArrayBlockingQueue 就是Queue的一種數(shù)組實現(xiàn)。 閱讀全文
對于一個Queue而言,同樣可以使用數(shù)組實現(xiàn)。使用數(shù)組的好處在于各個元素之間原生就是通過數(shù)組的索引關(guān)聯(lián)起來的,一次元素之間就是有序的,在通過索引操作數(shù)組就方便多了。當(dāng)然也有它不利的一面,擴(kuò)容起來比較麻煩,同時刪除一個元素也比較低效。
ArrayBlockingQueue 就是Queue的一種數(shù)組實現(xiàn)。 閱讀全文
摘要: 在《并發(fā)容器 part 4 并發(fā)隊列與Queue簡介》節(jié)中的類圖中可以看到,對于Queue來說,BlockingQueue是主要的線程安全版本。這是一個可阻塞的版本,也就是允許添加/刪除元素被阻塞,直到成功為止。
BlockingQueue相對于Queue而言增加了兩個操作:put/take。下面是一張整理的表格。 閱讀全文
BlockingQueue相對于Queue而言增加了兩個操作:put/take。下面是一張整理的表格。 閱讀全文
摘要: ConcurrentLinkedQueue是Queue的一個線程安全實現(xiàn)。先來看一段文檔說明。
一個基于鏈接節(jié)點的無界線程安全隊列。此隊列按照 FIFO(先進(jìn)先出)原則對元素進(jìn)行排序。隊列的頭部 是隊列中時間最長的元素。隊列的尾部 是隊列中時間最短的元素。新的元素插入到隊列的尾部,隊列獲取操作從隊列頭部獲得元素。當(dāng)多個線程共享訪問一個公共 collection 時,ConcurrentLinkedQueue 是一個恰當(dāng)?shù)倪x擇。此隊列不允許使用 null 元素。
由于ConcurrentLinkedQueue只是簡單的實現(xiàn)了一個隊列Queue,因此從API的角度講,沒有多少值的介紹,使用起來也很簡單,和前面遇到的所有FIFO隊列都類似。出隊列只能操作頭節(jié)點,入隊列只能操作尾節(jié)點,任意節(jié)點操作就需要遍歷完整的隊列。
重點放在解釋ConcurrentLinkedQueue的原理和實現(xiàn)上。 閱讀全文
一個基于鏈接節(jié)點的無界線程安全隊列。此隊列按照 FIFO(先進(jìn)先出)原則對元素進(jìn)行排序。隊列的頭部 是隊列中時間最長的元素。隊列的尾部 是隊列中時間最短的元素。新的元素插入到隊列的尾部,隊列獲取操作從隊列頭部獲得元素。當(dāng)多個線程共享訪問一個公共 collection 時,ConcurrentLinkedQueue 是一個恰當(dāng)?shù)倪x擇。此隊列不允許使用 null 元素。
由于ConcurrentLinkedQueue只是簡單的實現(xiàn)了一個隊列Queue,因此從API的角度講,沒有多少值的介紹,使用起來也很簡單,和前面遇到的所有FIFO隊列都類似。出隊列只能操作頭節(jié)點,入隊列只能操作尾節(jié)點,任意節(jié)點操作就需要遍歷完整的隊列。
重點放在解釋ConcurrentLinkedQueue的原理和實現(xiàn)上。 閱讀全文
摘要: Queue是JDK 5以后引入的新的集合類,它屬于Java Collections Framework的成員,在Collection集合中和List/Set是同一級別的接口。通常來講Queue描述的是一種FIFO的隊列,當(dāng)然不全都是,比如PriorityQueue是按照優(yōu)先級的順序(或者說是自然順序,借助于Comparator接口)。
下圖描述了Java Collections Framework中Queue的整個家族體系。
對于Queue而言是在Collection的基礎(chǔ)上增加了offer/remove/poll/element/peek方法,另外重新定義了add方法。對于這六個方法,有不同的定義。 閱讀全文
下圖描述了Java Collections Framework中Queue的整個家族體系。
對于Queue而言是在Collection的基礎(chǔ)上增加了offer/remove/poll/element/peek方法,另外重新定義了add方法。對于這六個方法,有不同的定義。 閱讀全文
摘要: 在上一篇中介紹了HashMap的原理,這一節(jié)是ConcurrentMap的最后一節(jié),所以會完整的介紹ConcurrentHashMap的實現(xiàn)。
ConcurrentHashMap原理
在讀寫鎖章節(jié)部分介紹過一種是用讀寫鎖實現(xiàn)Map的方法。此種方法看起來可以實現(xiàn)Map響應(yīng)的功能,而且吞吐量也應(yīng)該不錯。但是通過前面對讀寫鎖原理的分析后知道,讀寫鎖的適合場景是讀操作>>寫操作,也就是讀操作應(yīng)該占據(jù)大部分操作,另外讀寫鎖存在一個很嚴(yán)重的問題是讀寫操作不能同時發(fā)生。要想解決讀寫同時進(jìn)行問題(至少不同元素的讀寫分離),那么就只能將鎖拆分,不同的元素?fù)碛胁煌逆i,這種技術(shù)就是“鎖分離”技術(shù)。
默認(rèn)情況下ConcurrentHashMap是用了16個類似HashMap 的結(jié)構(gòu),其中每一個HashMap擁有一個獨占鎖。也就是說最終的效果就是通過某種Hash算法,將任何一個元素均勻的映射到某個HashMap的Map.Entry上面,而對某個一個元素的操作就集中在其分布的HashMap上,與其它HashMap無關(guān)。這樣就支持最多16個并發(fā)的寫操作。 閱讀全文
ConcurrentHashMap原理
在讀寫鎖章節(jié)部分介紹過一種是用讀寫鎖實現(xiàn)Map的方法。此種方法看起來可以實現(xiàn)Map響應(yīng)的功能,而且吞吐量也應(yīng)該不錯。但是通過前面對讀寫鎖原理的分析后知道,讀寫鎖的適合場景是讀操作>>寫操作,也就是讀操作應(yīng)該占據(jù)大部分操作,另外讀寫鎖存在一個很嚴(yán)重的問題是讀寫操作不能同時發(fā)生。要想解決讀寫同時進(jìn)行問題(至少不同元素的讀寫分離),那么就只能將鎖拆分,不同的元素?fù)碛胁煌逆i,這種技術(shù)就是“鎖分離”技術(shù)。
默認(rèn)情況下ConcurrentHashMap是用了16個類似HashMap 的結(jié)構(gòu),其中每一個HashMap擁有一個獨占鎖。也就是說最終的效果就是通過某種Hash算法,將任何一個元素均勻的映射到某個HashMap的Map.Entry上面,而對某個一個元素的操作就集中在其分布的HashMap上,與其它HashMap無關(guān)。這樣就支持最多16個并發(fā)的寫操作。 閱讀全文
摘要: 本來想比較全面和深入的談?wù)凜oncurrentHashMap的,發(fā)現(xiàn)網(wǎng)上有很多對HashMap和ConcurrentHashMap分析的文章,因此本小節(jié)盡可能的分析其中的細(xì)節(jié),少一點理論的東西,多談?wù)剝?nèi)部設(shè)計的原理和思想。
要談ConcurrentHashMap的構(gòu)造,就不得不談HashMap的構(gòu)造,因此先從HashMap開始簡單介紹。
HashMap原理
我們從頭開始設(shè)想。要將對象存放在一起,如何設(shè)計這個容器。目前只有兩條路可以走,一種是采用分格技術(shù),每一個對象存放于一個格子中,這樣通過對格子的編號就能取到或者遍歷對象;另一種技術(shù)就是采用串聯(lián)的方式,將各個對象串聯(lián)起來,這需要各個對象至少帶有下一個對象的索引(或者指針)。顯然第一種就是數(shù)組的概念,第二種就是鏈表的概念。所有的容器的實現(xiàn)其實都是基于這兩種方式的,不管是數(shù)組還是鏈表,或者二者俱有。HashMap采用的就是數(shù)組的方式。
有了存取對象的容器后還需要以下兩個條件才能完成Map所需要的條件。 閱讀全文
要談ConcurrentHashMap的構(gòu)造,就不得不談HashMap的構(gòu)造,因此先從HashMap開始簡單介紹。
HashMap原理
我們從頭開始設(shè)想。要將對象存放在一起,如何設(shè)計這個容器。目前只有兩條路可以走,一種是采用分格技術(shù),每一個對象存放于一個格子中,這樣通過對格子的編號就能取到或者遍歷對象;另一種技術(shù)就是采用串聯(lián)的方式,將各個對象串聯(lián)起來,這需要各個對象至少帶有下一個對象的索引(或者指針)。顯然第一種就是數(shù)組的概念,第二種就是鏈表的概念。所有的容器的實現(xiàn)其實都是基于這兩種方式的,不管是數(shù)組還是鏈表,或者二者俱有。HashMap采用的就是數(shù)組的方式。
有了存取對象的容器后還需要以下兩個條件才能完成Map所需要的條件。 閱讀全文
摘要: 從這一節(jié)開始正式進(jìn)入并發(fā)容器的部分,來看看JDK 6帶來了哪些并發(fā)容器。
在JDK 1.4以下只有Vector和Hashtable是線程安全的集合(也稱并發(fā)容器,Collections.synchronized*系列也可以看作是線程安全的實現(xiàn))。從JDK 5開始增加了線程安全的Map接口ConcurrentMap和線程安全的隊列BlockingQueue(盡管Queue也是同時期引入的新的集合,但是規(guī)范并沒有規(guī)定一定是線程安全的,事實上一些實現(xiàn)也不是線程安全的,比如PriorityQueue、ArrayDeque、LinkedList等,在Queue章節(jié)中會具體討論這些隊列的結(jié)構(gòu)圖和實現(xiàn))。
在介紹ConcurrencyMap之前先來回顧下Map的體系結(jié)構(gòu)。下圖描述了Map的體系結(jié)構(gòu),其中藍(lán)色字體的是JDK 5以后新增的并發(fā)容器。 閱讀全文
在JDK 1.4以下只有Vector和Hashtable是線程安全的集合(也稱并發(fā)容器,Collections.synchronized*系列也可以看作是線程安全的實現(xiàn))。從JDK 5開始增加了線程安全的Map接口ConcurrentMap和線程安全的隊列BlockingQueue(盡管Queue也是同時期引入的新的集合,但是規(guī)范并沒有規(guī)定一定是線程安全的,事實上一些實現(xiàn)也不是線程安全的,比如PriorityQueue、ArrayDeque、LinkedList等,在Queue章節(jié)中會具體討論這些隊列的結(jié)構(gòu)圖和實現(xiàn))。
在介紹ConcurrencyMap之前先來回顧下Map的體系結(jié)構(gòu)。下圖描述了Map的體系結(jié)構(gòu),其中藍(lán)色字體的是JDK 5以后新增的并發(fā)容器。 閱讀全文
摘要:
主要談?wù)勬i的性能以及其它一些理論知識,內(nèi)容主要的出處是《Java Concurrency in Practice》,結(jié)合自己的理解和實際應(yīng)用對鎖機(jī)制進(jìn)行一個小小的總結(jié)。
首先需要強調(diào)的一點是:所有鎖(包括內(nèi)置鎖和高級鎖)都是有性能消耗的,也就是說在高并發(fā)的情況下,由于鎖機(jī)制帶來的上下文切換、資源同步等消耗是非常可觀的。在某些極端情況下,線程在鎖上的消耗可能比線程本身的消耗還要多。所以如果可能的話,在任何情況下都盡量少用鎖,如果不可避免那么采用非阻塞算法是一個不錯的解決方案,但是卻也不是絕對的。 閱讀全文
主要談?wù)勬i的性能以及其它一些理論知識,內(nèi)容主要的出處是《Java Concurrency in Practice》,結(jié)合自己的理解和實際應(yīng)用對鎖機(jī)制進(jìn)行一個小小的總結(jié)。
首先需要強調(diào)的一點是:所有鎖(包括內(nèi)置鎖和高級鎖)都是有性能消耗的,也就是說在高并發(fā)的情況下,由于鎖機(jī)制帶來的上下文切換、資源同步等消耗是非常可觀的。在某些極端情況下,線程在鎖上的消耗可能比線程本身的消耗還要多。所以如果可能的話,在任何情況下都盡量少用鎖,如果不可避免那么采用非阻塞算法是一個不錯的解決方案,但是卻也不是絕對的。 閱讀全文
摘要:
這一節(jié)主要是談?wù)勛x寫鎖的實現(xiàn)。
上一節(jié)中提到,ReadWriteLock看起來有兩個鎖:readLock/writeLock。如果真的是兩個鎖的話,它們之間又是如何相互影響的呢?
事實上在ReentrantReadWriteLock里鎖的實現(xiàn)是靠java.util.concurrent.locks.ReentrantReadWriteLock.Sync完成的。這個類看起來比較眼熟,實際上它是AQS的一個子類,這中類似的結(jié)構(gòu)在CountDownLatch、ReentrantLock、Semaphore里面都存在。同樣它也有兩種實現(xiàn):公平鎖和非公平鎖,也就是java.util.concurrent.locks.ReentrantReadWriteLock.FairSync和java.util.concurrent.locks.ReentrantReadWriteLock.NonfairSync。這里暫且不提。
在ReentrantReadWriteLock里面的鎖主體就是一個Sync,也就是上面提到的FairSync或者NonfairSync,所以說實際 閱讀全文
這一節(jié)主要是談?wù)勛x寫鎖的實現(xiàn)。
上一節(jié)中提到,ReadWriteLock看起來有兩個鎖:readLock/writeLock。如果真的是兩個鎖的話,它們之間又是如何相互影響的呢?
事實上在ReentrantReadWriteLock里鎖的實現(xiàn)是靠java.util.concurrent.locks.ReentrantReadWriteLock.Sync完成的。這個類看起來比較眼熟,實際上它是AQS的一個子類,這中類似的結(jié)構(gòu)在CountDownLatch、ReentrantLock、Semaphore里面都存在。同樣它也有兩種實現(xiàn):公平鎖和非公平鎖,也就是java.util.concurrent.locks.ReentrantReadWriteLock.FairSync和java.util.concurrent.locks.ReentrantReadWriteLock.NonfairSync。這里暫且不提。
在ReentrantReadWriteLock里面的鎖主體就是一個Sync,也就是上面提到的FairSync或者NonfairSync,所以說實際 閱讀全文
摘要: 從這一節(jié)開始介紹鎖里面的最后一個工具:讀寫鎖(ReadWriteLock)。
ReentrantLock 實現(xiàn)了標(biāo)準(zhǔn)的互斥操作,也就是一次只能有一個線程持有鎖,也即所謂獨占鎖的概念。前面的章節(jié)中一直在強調(diào)這個特點。顯然這個特點在一定程度上面減低了吞吐量,實際上獨占鎖是一種保守的鎖策略,在這種情況下任何“讀/讀”,“寫/讀”,“寫/寫”操作都不能同時發(fā)生。但是同樣需要強調(diào)的一個概念是,鎖是有一定的開銷的,當(dāng)并發(fā)比較大的時候,鎖的開銷就比較客觀了。所以如果可能的話就盡量少用鎖,非要用鎖的話就嘗試看能否改造為讀寫鎖。
ReadWriteLock描述的是:一個資源能夠被多個讀線程訪問,或者被一個寫線程訪問,但是不能同時存在讀寫線程。也就是說讀寫鎖使用的場合是一個共享資源被大量讀取操作,而只有少量的寫操作(修改數(shù)據(jù))。清單1描述了ReadWriteLock的API。 閱讀全文
ReentrantLock 實現(xiàn)了標(biāo)準(zhǔn)的互斥操作,也就是一次只能有一個線程持有鎖,也即所謂獨占鎖的概念。前面的章節(jié)中一直在強調(diào)這個特點。顯然這個特點在一定程度上面減低了吞吐量,實際上獨占鎖是一種保守的鎖策略,在這種情況下任何“讀/讀”,“寫/讀”,“寫/寫”操作都不能同時發(fā)生。但是同樣需要強調(diào)的一個概念是,鎖是有一定的開銷的,當(dāng)并發(fā)比較大的時候,鎖的開銷就比較客觀了。所以如果可能的話就盡量少用鎖,非要用鎖的話就嘗試看能否改造為讀寫鎖。
ReadWriteLock描述的是:一個資源能夠被多個讀線程訪問,或者被一個寫線程訪問,但是不能同時存在讀寫線程。也就是說讀寫鎖使用的場合是一個共享資源被大量讀取操作,而只有少量的寫操作(修改數(shù)據(jù))。清單1描述了ReadWriteLock的API。 閱讀全文
摘要: Semaphore 是一個計數(shù)信號量。從概念上講,信號量維護(hù)了一個許可集。如有必要,在許可可用前會阻塞每一個 acquire(),然后再獲取該許可。每個 release() 添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可對象,Semaphore 只對可用許可的號碼進(jìn)行計數(shù),并采取相應(yīng)的行動。
說白了,Semaphore是一個計數(shù)器,在計數(shù)器不為0的時候?qū)€程就放行,一旦達(dá)到0,那么所有請求資源的新線程都會被阻塞,包括增加請求到許可的線程,也就是說Semaphore不是可重入的。每一次請求一個許可都會導(dǎo)致計數(shù)器減少1,同樣每次釋放一個許可都會導(dǎo)致計數(shù)器增加1,一旦達(dá)到了0,新的許可請求線程將被掛起。
緩存池整好使用此思想來實現(xiàn)的,比如鏈接池、對象池等。 閱讀全文
說白了,Semaphore是一個計數(shù)器,在計數(shù)器不為0的時候?qū)€程就放行,一旦達(dá)到0,那么所有請求資源的新線程都會被阻塞,包括增加請求到許可的線程,也就是說Semaphore不是可重入的。每一次請求一個許可都會導(dǎo)致計數(shù)器減少1,同樣每次釋放一個許可都會導(dǎo)致計數(shù)器增加1,一旦達(dá)到了0,新的許可請求線程將被掛起。
緩存池整好使用此思想來實現(xiàn)的,比如鏈接池、對象池等。 閱讀全文
摘要:
如果說CountDownLatch是一次性的,那么CyclicBarrier正好可以循環(huán)使用。它允許一組線程互相等待,直到到達(dá)某個公共屏障點 (common barrier point)。所謂屏障點就是一組任務(wù)執(zhí)行完畢的時刻。
閱讀全文
如果說CountDownLatch是一次性的,那么CyclicBarrier正好可以循環(huán)使用。它允許一組線程互相等待,直到到達(dá)某個公共屏障點 (common barrier point)。所謂屏障點就是一組任務(wù)執(zhí)行完畢的時刻。
閱讀全文
摘要: 此小節(jié)介紹幾個與鎖有關(guān)的有用工具。
閉鎖(Latch)
閉鎖(Latch):一種同步方法,可以延遲線程的進(jìn)度直到線程到達(dá)某個終點狀態(tài)。通俗的講就是,一個閉鎖相當(dāng)于一扇大門,在大門打開之前所有線程都被阻斷,一旦大門打開所有線程都將通過,但是一旦大門打開,所有線程都通過了,那么這個閉鎖的狀態(tài)就失效了,門的狀態(tài)也就不能變了,只能是打開狀態(tài)。也就是說閉鎖的狀態(tài)是一次性的,它確保在閉鎖打開之前所有特定的活動都需要在閉鎖打開之后才能完成。
CountDownLatch是JDK 5+里面閉鎖的一個實現(xiàn),允許一個或者多個線程等待某個事件的發(fā)生。CountDownLatch有一個正數(shù)計數(shù)器,countDown方法對計數(shù)器做減操作,await方法等待計數(shù)器達(dá)到0。所有await的線程都會阻塞直到計數(shù)器為0或者等待線程中斷或者超時。 閱讀全文
閉鎖(Latch)
閉鎖(Latch):一種同步方法,可以延遲線程的進(jìn)度直到線程到達(dá)某個終點狀態(tài)。通俗的講就是,一個閉鎖相當(dāng)于一扇大門,在大門打開之前所有線程都被阻斷,一旦大門打開所有線程都將通過,但是一旦大門打開,所有線程都通過了,那么這個閉鎖的狀態(tài)就失效了,門的狀態(tài)也就不能變了,只能是打開狀態(tài)。也就是說閉鎖的狀態(tài)是一次性的,它確保在閉鎖打開之前所有特定的活動都需要在閉鎖打開之后才能完成。
CountDownLatch是JDK 5+里面閉鎖的一個實現(xiàn),允許一個或者多個線程等待某個事件的發(fā)生。CountDownLatch有一個正數(shù)計數(shù)器,countDown方法對計數(shù)器做減操作,await方法等待計數(shù)器達(dá)到0。所有await的線程都會阻塞直到計數(shù)器為0或者等待線程中斷或者超時。 閱讀全文
摘要: 這是一份完整的Java 并發(fā)整理筆記,記錄了我最近幾年學(xué)習(xí)Java并發(fā)的一些心得和體會。 閱讀全文
摘要: 接上篇,這篇從Lock.lock/unlock開始。特別說明在沒有特殊情況下所有程序、API、文檔都是基于JDK 6.0的。
在沒有深入了解內(nèi)部機(jī)制及實現(xiàn)之前,先了解下為什么會存在公平鎖和非公平鎖。公平鎖保證一個阻塞的線程最終能夠獲得鎖,因為是有序的,所以總是可以按照請求的順序獲得鎖。不公平鎖意味著后請求鎖的線程可能在其前面排列的休眠線程恢復(fù)前拿到鎖,這樣就有可能提高并發(fā)的性能。這是因為通常情況下掛起的線程重新開始與它真正開始運行,二者之間會產(chǎn)生嚴(yán)重的延時。因此非公平鎖就可以利用這段時間完成操作。這是非公平鎖在某些時候比公平鎖性能要好的原因之一。 閱讀全文
在沒有深入了解內(nèi)部機(jī)制及實現(xiàn)之前,先了解下為什么會存在公平鎖和非公平鎖。公平鎖保證一個阻塞的線程最終能夠獲得鎖,因為是有序的,所以總是可以按照請求的順序獲得鎖。不公平鎖意味著后請求鎖的線程可能在其前面排列的休眠線程恢復(fù)前拿到鎖,這樣就有可能提高并發(fā)的性能。這是因為通常情況下掛起的線程重新開始與它真正開始運行,二者之間會產(chǎn)生嚴(yán)重的延時。因此非公平鎖就可以利用這段時間完成操作。這是非公平鎖在某些時候比公平鎖性能要好的原因之一。 閱讀全文
摘要: 在理解J.U.C原理以及鎖機(jī)制之前,我們來介紹J.U.C框架最核心也是最復(fù)雜的一個基礎(chǔ)類:java.util.concurrent.locks.AbstractQueuedSynchronizer。
AQS
AbstractQueuedSynchronizer,簡稱AQS,是J.U.C最復(fù)雜的一個類,導(dǎo)致絕大多數(shù)講解并發(fā)原理或者實戰(zhàn)的時候都不會提到此類。但是虛心的作者愿意借助自己有限的能力和精力來探討一二(參考資源中也有一些作者做了部分的分析。)。
首先從理論知識開始,在了解了相關(guān)原理后會針對源碼進(jìn)行一些分析,最后加上一些實戰(zhàn)來描述。 閱讀全文
AQS
AbstractQueuedSynchronizer,簡稱AQS,是J.U.C最復(fù)雜的一個類,導(dǎo)致絕大多數(shù)講解并發(fā)原理或者實戰(zhàn)的時候都不會提到此類。但是虛心的作者愿意借助自己有限的能力和精力來探討一二(參考資源中也有一些作者做了部分的分析。)。
首先從理論知識開始,在了解了相關(guān)原理后會針對源碼進(jìn)行一些分析,最后加上一些實戰(zhàn)來描述。 閱讀全文
摘要: 前面的章節(jié)主要談?wù)勗硬僮鳎劣谂c原子操作一些相關(guān)的問題或者說陷阱就放到最后的總結(jié)篇來整體說明。從這一章開始花少量的篇幅談?wù)勬i機(jī)制。
上一個章節(jié)中談到了鎖機(jī)制,并且針對于原子操作談了一些相關(guān)的概念和設(shè)計思想。接下來的文章中,盡可能的深入研究鎖機(jī)制,并且理解里面的原理和實際應(yīng)用場合。
盡管synchronized在語法上已經(jīng)足夠簡單了,在JDK 5之前只能借助此實現(xiàn),但是由于是獨占鎖,性能卻不高,因此JDK 5以后就開始借助于JNI來完成更高級的鎖實現(xiàn)。
JDK 5中的鎖是接口java.util.concurrent.locks.Lock。另外java.util.concurrent.locks.ReadWriteLock提供了一對可供讀寫并發(fā)的鎖。根據(jù)前面的規(guī)則,我們從java.util.concurrent.locks.Lock的API開始。 閱讀全文
上一個章節(jié)中談到了鎖機(jī)制,并且針對于原子操作談了一些相關(guān)的概念和設(shè)計思想。接下來的文章中,盡可能的深入研究鎖機(jī)制,并且理解里面的原理和實際應(yīng)用場合。
盡管synchronized在語法上已經(jīng)足夠簡單了,在JDK 5之前只能借助此實現(xiàn),但是由于是獨占鎖,性能卻不高,因此JDK 5以后就開始借助于JNI來完成更高級的鎖實現(xiàn)。
JDK 5中的鎖是接口java.util.concurrent.locks.Lock。另外java.util.concurrent.locks.ReadWriteLock提供了一對可供讀寫并發(fā)的鎖。根據(jù)前面的規(guī)則,我們從java.util.concurrent.locks.Lock的API開始。 閱讀全文
摘要: 在JDK 5之前Java語言是靠synchronized關(guān)鍵字保證同步的,這會導(dǎo)致有鎖(后面的章節(jié)還會談到鎖)。
鎖機(jī)制存在以下問題:
(1)在多線程競爭下,加鎖、釋放鎖會導(dǎo)致比較多的上下文切換和調(diào)度延時,引起性能問題。
(2)一個線程持有鎖會導(dǎo)致其它所有需要此鎖的線程掛起。
(3)如果一個優(yōu)先級高的線程等待一個優(yōu)先級低的線程釋放鎖會導(dǎo)致優(yōu)先級倒置,引起性能風(fēng)險。
volatile是不錯的機(jī)制,但是volatile不能保證原子性。因此對于同步最終還是要回到鎖機(jī)制上來。
獨占鎖是一種悲觀鎖,synchronized就是一種獨占鎖,會導(dǎo)致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。而另一個更加有效的鎖就是樂觀鎖。所謂樂觀鎖就是,每次不加鎖而是假設(shè)沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。 閱讀全文
鎖機(jī)制存在以下問題:
(1)在多線程競爭下,加鎖、釋放鎖會導(dǎo)致比較多的上下文切換和調(diào)度延時,引起性能問題。
(2)一個線程持有鎖會導(dǎo)致其它所有需要此鎖的線程掛起。
(3)如果一個優(yōu)先級高的線程等待一個優(yōu)先級低的線程釋放鎖會導(dǎo)致優(yōu)先級倒置,引起性能風(fēng)險。
volatile是不錯的機(jī)制,但是volatile不能保證原子性。因此對于同步最終還是要回到鎖機(jī)制上來。
獨占鎖是一種悲觀鎖,synchronized就是一種獨占鎖,會導(dǎo)致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。而另一個更加有效的鎖就是樂觀鎖。所謂樂觀鎖就是,每次不加鎖而是假設(shè)沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。 閱讀全文
摘要: 在這個小結(jié)里面重點討論原子操作的原理和設(shè)計思想。
由于在下一個章節(jié)中會談到鎖機(jī)制,因此此小節(jié)中會適當(dāng)引入鎖的概念。
在Java Concurrency in Practice中是這樣定義線程安全的:
當(dāng)多個線程訪問一個類時,如果不用考慮這些線程在運行時環(huán)境下的調(diào)度和交替運行,并且不需要額外的同步及在調(diào)用方代碼不必做其他的協(xié)調(diào),這個類的行為仍然是正確的,那么這個類就是線程安全的。 閱讀全文
由于在下一個章節(jié)中會談到鎖機(jī)制,因此此小節(jié)中會適當(dāng)引入鎖的概念。
在Java Concurrency in Practice中是這樣定義線程安全的:
當(dāng)多個線程訪問一個類時,如果不用考慮這些線程在運行時環(huán)境下的調(diào)度和交替運行,并且不需要額外的同步及在調(diào)用方代碼不必做其他的協(xié)調(diào),這個類的行為仍然是正確的,那么這個類就是線程安全的。 閱讀全文
摘要: 在這一部分開始討論數(shù)組原子操作和一些其他的原子操作。
AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API類似,選擇有代表性的AtomicIntegerArray來描述這些問題。
int get(int i)
獲取位置 i 的當(dāng)前值。很顯然,由于這個是數(shù)組操作,就有索引越界的問題(IndexOutOfBoundsException異常)。
對于下面的API起始和AtomicInteger是類似的,這種通過方法、參數(shù)的名稱就能夠得到函數(shù)意義的寫法是非常值得稱贊的。在《重構(gòu):改善既有代碼的設(shè)計》和《代碼整潔之道》中都非常推崇這種做法。 閱讀全文
AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API類似,選擇有代表性的AtomicIntegerArray來描述這些問題。
int get(int i)
獲取位置 i 的當(dāng)前值。很顯然,由于這個是數(shù)組操作,就有索引越界的問題(IndexOutOfBoundsException異常)。
對于下面的API起始和AtomicInteger是類似的,這種通過方法、參數(shù)的名稱就能夠得到函數(shù)意義的寫法是非常值得稱贊的。在《重構(gòu):改善既有代碼的設(shè)計》和《代碼整潔之道》中都非常推崇這種做法。 閱讀全文
摘要: 從相對簡單的Atomic入手(java.util.concurrent是基于Queue的并發(fā)包,而Queue,很多情況下使用到了Atomic操作,因此首先從這里開始)。很多情況下我們只是需要一個簡單的、高效的、線程安全的遞增遞減方案。注意,這里有三個條件:簡單,意味著程序員盡可能少的操作底層或者實現(xiàn)起來要比較容易;高效意味著耗用資源要少,程序處理速度要快;線程安全也非常重要,這個在多線程下能保證數(shù)據(jù)的正確性。這三個條件看起來比較簡單,但是實現(xiàn)起來卻難以令人滿意。
通常情況下,在Java里面,++i或者--i不是線程安全的,這里面有三個獨立的操作:或者變量當(dāng)前值,為該值+1/-1,然后寫回新的值。在沒有額外資源可以利用的情況下,只能使用加鎖才能保證讀-改-寫這三個操作時“原子性”的。 閱讀全文
通常情況下,在Java里面,++i或者--i不是線程安全的,這里面有三個獨立的操作:或者變量當(dāng)前值,為該值+1/-1,然后寫回新的值。在沒有額外資源可以利用的情況下,只能使用加鎖才能保證讀-改-寫這三個操作時“原子性”的。 閱讀全文
摘要: 去年年底有一個Guice的研究計劃,可惜由于工作“繁忙”加上實際工作中沒有用上導(dǎo)致“無疾而終”,最終只是完成了Guice的初步學(xué)習(xí)教程,深入的研究沒有繼續(xù)進(jìn)行下去。
最近一直用的比較多的就是java.util.concurrent(J.U.C),實際上這塊一直也沒有完全深入研究,這次準(zhǔn)備花點時間研究下Java里面整個并發(fā)體系。初步的設(shè)想包括比較大的方便(包括硬件、軟件、思想以及誤區(qū)等等),因此可能會持續(xù)較長的時間。這塊內(nèi)容也是Java在多線程方面引以為豪的一部分,深入這一部分不僅對整個Java體系有更深的了解,也對工作、學(xué)習(xí)的態(tài)度有多幫助。 閱讀全文
最近一直用的比較多的就是java.util.concurrent(J.U.C),實際上這塊一直也沒有完全深入研究,這次準(zhǔn)備花點時間研究下Java里面整個并發(fā)體系。初步的設(shè)想包括比較大的方便(包括硬件、軟件、思想以及誤區(qū)等等),因此可能會持續(xù)較長的時間。這塊內(nèi)容也是Java在多線程方面引以為豪的一部分,深入這一部分不僅對整個Java體系有更深的了解,也對工作、學(xué)習(xí)的態(tài)度有多幫助。 閱讀全文