java 对象锁定_少锁定Java对象池
java 對(duì)象鎖定
自從我寫(xiě)任何東西以來(lái)已經(jīng)有一段時(shí)間了,我一直在忙于我的新工作,其中涉及在性能調(diào)優(yōu)方面做一些有趣的工作。 挑戰(zhàn)之一是減少應(yīng)用程序關(guān)鍵部分的對(duì)象創(chuàng)建。
盡管Java隨著時(shí)間的推移已改進(jìn)了GC算法,但垃圾回收打ic一直是Java的主要難題。 Azul是開(kāi)發(fā)無(wú)暫停GC的市場(chǎng)領(lǐng)導(dǎo)者,但Azul JVM并非免費(fèi)!
創(chuàng)建過(guò)多的臨時(shí)/垃圾對(duì)象并不能很好地工作,因?yàn)樗鼮镚C創(chuàng)建了工作,并且將對(duì)延遲產(chǎn)生負(fù)面影響。 過(guò)多的垃圾也不能在多核系統(tǒng)上正常工作,因?yàn)樗鼤?huì)導(dǎo)致緩存污染。
那么我們應(yīng)該如何解決呢?
垃圾少編碼
僅當(dāng)您知道需要多少個(gè)對(duì)象并預(yù)先分配它們時(shí),這才有可能,但是實(shí)際上很難找到。 但是即使您成功做到了,也必須擔(dān)心另一個(gè)問(wèn)題
- 您可能沒(méi)有足夠的內(nèi)存來(lái)容納所需的所有對(duì)象
- 您還必須處理并發(fā)
那么上述問(wèn)題的解決方案是什么
有一種對(duì)象池設(shè)計(jì)模式可以解決以上兩個(gè)問(wèn)題。 它使您可以指定池中所需的許多對(duì)象,并處理并發(fā)請(qǐng)求以服務(wù)所請(qǐng)求的對(duì)象。
對(duì)象池一直是許多具有低延遲要求的應(yīng)用程序的基礎(chǔ)。 Flyweight設(shè)計(jì)模式是對(duì)象池的一種風(fēng)格。
上面的兩種模式都將幫助我們避免創(chuàng)建對(duì)象。 太好了,因此現(xiàn)在減少了GC工作,并且理論上我們的應(yīng)用程序性能應(yīng)該得到改善。 實(shí)際上,不會(huì)那樣做,因?yàn)閷?duì)象池/ Flyweight必須處理并發(fā),并且由于并發(fā)問(wèn)題而失去了避免對(duì)象創(chuàng)建而獲得的任何優(yōu)勢(shì)。
處理并發(fā)的最常見(jiàn)方法是什么
對(duì)象池是一個(gè)典型的生產(chǎn)者/消費(fèi)者問(wèn)題,可以使用以下技術(shù)來(lái)解決:
同步:這是在JDK 1.5之前處理并發(fā)的唯一方法。 Apache編寫(xiě)了一個(gè)基于同步的出色的對(duì)象池 API
鎖: Java在JDK 1.5之后增加了對(duì)并發(fā)編程的出色支持。 已經(jīng)有一些使用鎖來(lái)開(kāi)發(fā)對(duì)象池的工作,例如, furious-objectpool
無(wú)鎖:我找不到使用完全無(wú)鎖技術(shù)構(gòu)建的任何實(shí)現(xiàn),但是furious-objectpool使用ArrayBlocking隊(duì)列和ConcurrentLinked隊(duì)列的混合
衡量績(jī)效
在此測(cè)試中,我創(chuàng)建了一個(gè)包含100萬(wàn)個(gè)對(duì)象的池,并且這些對(duì)象可以通過(guò)不同的池實(shí)現(xiàn)進(jìn)行訪問(wèn),這些對(duì)象將從池中取出并返回到池中。
該測(cè)試首先從1個(gè)線程開(kāi)始,然后增加線程數(shù)以衡量不同池在爭(zhēng)用情況下的執(zhí)行情況
- X軸–螺紋數(shù)
- Y軸–以毫秒為單位的時(shí)間–越短的時(shí)間越好
該測(cè)試包括來(lái)自Apache的池,Furious池和基于ArrayBlocking的池
Apache的性能最差,并且隨著線程數(shù)量的增加,性能會(huì)進(jìn)一步下降。 原因是Apache池基于大量使用“同步”
其他兩個(gè)(基于Furious和ArrayBlocking的池)的性能更好,但是隨著爭(zhēng)用的增加,它們兩者的速度也會(huì)降低。
當(dāng)12個(gè)線程試圖訪問(wèn)該池時(shí),基于ArrayBlocking隊(duì)列的池對(duì)于100萬(wàn)個(gè)項(xiàng)目大約需要1000毫秒。 內(nèi)部使用Arrayblocking隊(duì)列的憤怒池大約需要1975 ms。
我必須進(jìn)行更詳細(xì)的調(diào)查,以找出為什么Furious花費(fèi)雙倍的時(shí)間,因?yàn)樗彩腔贏rrayBlocking隊(duì)列的。
數(shù)組阻塞隊(duì)列的性能不錯(cuò),但這是一種基于鎖定的方法。 如果可以實(shí)現(xiàn)無(wú)鎖池,我們將獲得哪種類(lèi)型的性能?
鎖免費(fèi)游泳池
實(shí)現(xiàn)無(wú)鎖池不是不可能的,但是有點(diǎn)困難,因?yàn)槟仨毺幚矶鄠€(gè)生產(chǎn)者和消費(fèi)者。
我將實(shí)現(xiàn)一個(gè)混合池,該池將在生產(chǎn)者端使用鎖定,而在消費(fèi)者端使用非阻塞技術(shù)。
讓我們看一些數(shù)字
我使用新的實(shí)現(xiàn)(FastPool)進(jìn)行了相同的測(cè)試,它比ArayBlocking隊(duì)列快了30%。
30%的改善還不錯(cuò),它絕對(duì)可以幫助我們實(shí)現(xiàn)延遲目標(biāo)。
是什么讓快速池快速!
我使用了兩種技術(shù)來(lái)使其快速運(yùn)行
- 生產(chǎn)者是基于鎖的–使用鎖來(lái)管理多個(gè)生產(chǎn)者,這與“數(shù)組阻止”隊(duì)列相同,因此沒(méi)什么大不了的。
- 立即發(fā)布已發(fā)布項(xiàng)目–在使用便宜的內(nèi)存屏障釋放鎖之前,它會(huì)發(fā)布元素。 這會(huì)有所收獲
- 消費(fèi)者不受阻礙–使用CAS來(lái)實(shí)現(xiàn)這一目標(biāo),消費(fèi)者永遠(yuǎn)不會(huì)因生產(chǎn)者而受到阻礙。 數(shù)組阻止隊(duì)列阻止使用者,因?yàn)樗鼘?duì)生產(chǎn)者和使用者使用相同的鎖
- 線程局部以保持值的局部性–線程局部用于獲取最后使用的值,這在很大程度上減少了爭(zhēng)用。
如果您有興趣查看代碼,則可以使用@ FastObjectPool.java
翻譯自: https://www.javacodegeeks.com/2013/07/lock-less-java-object-pool.html
java 對(duì)象鎖定
總結(jié)
以上是生活随笔為你收集整理的java 对象锁定_少锁定Java对象池的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 死亡骑士天赋冰霜加点(魔兽世界冰霜死亡骑
- 下一篇: WinXP系统怎么怎么恢复系统还原xp如