對象池作為全局資源诊霹,高并發(fā)環(huán)境中多個線程可能同時需要獲取對象池的對象,因此多個線程在爭搶對象時因為鎖競爭而阻塞渣淳,因此使用對象池有線程同步的開銷脾还,而不使用對象池則有創(chuàng)建和銷毀對象的開銷。對于對象池本身的設計來說入愧,需要盡量做到無鎖化鄙漏,比如Jetty就使用了ConcurrentLinkedDeque。如果你的內(nèi)存足夠大棺蛛,可以考慮線程本地對象池怔蚌,這樣每個線程都有自己的對象池,線程之間互不干擾旁赊。
為了防止對象池的無限膨脹桦踊,必須要對池的大小做限制。對象池太小發(fā)揮不了作用彤恶,對象池太大的話可能有空閑對象钞钙,這些空閑對象會一直占用內(nèi)存,造成內(nèi)存浪費声离。這里你需要根據(jù)實際情況做一個平衡芒炼,因此對象池本身除了應該有自動擴容的功能,還需要考慮自動縮容术徊。
所有的池化技術(shù)本刽,包括緩存,都會面臨內(nèi)存泄露的問題,原因是對象池或者緩存的本質(zhì)是一個Java集合類子寓,比如List和Stack暗挑,這個集合類持有緩存對象的引用,只要集合類不被GC斜友,緩存對象也不會被GC炸裆。維持大量的對象也比較占用內(nèi)存空間,所以必要時我們需要主動清理這些對象鲜屏。以Java的線程ThreadPoolExecutor
為例烹看,它提供了allowCoreThreadTimeOut和setKeepAliveTime兩種方法,可以在超時后銷毀線程洛史,我們在實際項目中也可以參考這個策略惯殊。
另外在使用對象池時,我這里還有一些小貼士供你參考:
- 對象在用完后也殖,需要調(diào)用對象池的方法將對象歸還給對象池土思。
- 對象池中的對象在再次使用時需要重置,否則會產(chǎn)生臟對象忆嗜,臟對象可能持有上次使用的引用己儒,導致內(nèi)存泄漏等問題,并且如果臟對象下一次使用時沒有被清理捆毫,程序在運行過程中會發(fā)生意想不到的問題址愿。
- 對象一旦歸還給對象池,使用者就不能對它做任何操作了冻璃。
- 向?qū)ο蟪卣埱髮ο髸r有可能出現(xiàn)的阻塞、異乘鸷希或者返回null值省艳,這些都需要我們做一些額外的處理,來確保程序的正常運行嫁审。