2016-03-08 96 views
2

1):單線程應用程序是否只在用戶的CPU上使用1個線程?會給更多的線程使用多個CPU內核?如果你聲明比用戶的CPU多的線程,會發生什麼? 2):只要你的方法沒有同步問題等,是否有任何性能損害爲你的每個方法創建新的線程? 3):我正在做一個遊戲,偶爾在收集垃圾時會有明顯的口吃。將垃圾收集器放在它自己的線程中解決了這個問題?Java多線程問題

+0

垃圾回收器運行在自己的線程(或線程)。雖然所有的GC實現都有一個「停止世界」的時刻,但調諧GC可以產生巨大的影響。 (首先創建更少的垃圾也有幫助:))這也回答了第一個問題:不,即使是「單線程」Java應用程序也會運行多個線程。 – biziclop

+0

但我看到的主要問題是,您認爲使用多個線程是性能問題的解決方案。實際上它很少,並且在問題中引發越來越多的線程可以很快開始**降低**性能。 – biziclop

+0

不要調用'System.gc();'一堆,這會導致性能問題,讓java自己做。 – BitNinja

回答

3

的問題問:

  1. 是,一個線程是指一個CPU線程。額外的線程可以使用額外的CPU,只要他們有工作要做。如果你創建的線程多於CPU,他們將爭取CPU時間,結果通常會變慢。一些CPU使用超線程,並且暴露比實際內核更多的線程(有時這會給性能帶來好處)。使用Runtime.getRuntime.availableProcessors()顯示建議的線程數。
  2. 是的,線程創建和銷燬並不便宜,並且有一個large overhead for each thread。由於這個原因,彙集和重用線程是一種非常常見的模式。不要爲每個方法調用創建一個線程。
  3. 垃圾收集器已經在單獨的線程中完成它的工作,但它必須導致至少部分GC停止「暫停世界」,以標記用於收集的死對象。

的問題,你需要的答案,這個問題你沒有問:

問:如何讓我這個跑得更快?

答:幾種方法:

  • 簡介:發現瓶頸在哪裏是在你的程序,並側重於。 10%的代碼通常會消耗90%的運行時間。
  • 在嘗試優化實現之前,重點關注算法。唯一比做昂貴的操作2x速度更快的是永遠不要必須這樣做。延遲加載和緩存結果可能是巨大的節省時間。
  • 使用一個主線程渲染和用戶交互,並在這裏做盡可能少的實際工作成爲可能。這使得系統對用戶響應。渲染應該只在創建新對象時發生變化。
  • 使用工作隊列和工作線程池長期運行的任務尤其是網絡請求或磁盤I/O可能會屏蔽的渲染和UI線程。所有你真正的工作應該是異步的。
  • 生成儘可能少的垃圾儘可能 - 不要做,當你不需要銷燬對象。垃圾回收應該是很少是Java程序的重要瓶頸。
  • 使用線程的磁盤I/O,多線程池中的網絡I/O,以及每個CPU有一個工作線程。

編輯:有人抱怨之前,異步I/O或非阻塞I/O性能比線程池的網絡請求更好,但他們也更復雜的新的開發人員正確地使用。只要你沒有寫網絡上的東西,一個適中大小的線程池就足以使網絡連接飽和,儘管有延遲。

如果您收到明顯的垃圾收集暫停,那麼你可能做錯了什麼。垃圾收集已經過優化,可以在最短的時間內獲得最多的結果。大多數時候,GC暫停會花費幾毫秒來做一個小GC(除非我們正在談論4+ GB的堆)。 不要明確地調用System.gc(),否則您會強制執行不需要的工作並導致暫停。

+0

太棒了!那些將成爲我的下一個問題! –

+0

@MitchWeaver這幾乎就像我以前遇到過這個問題;) – BobMcGee

2

1)除了JVM可能創建自己的線程(例如,垃圾收集在其自己的線程(或更多)中分離),您的應用程序可能只使用1個線程)。更多的線程使用更多的CPU,如果你有更多的線程比CPU調度器使線程輪流(上下文切換)。

2)過多的上下文切換(來自調度程序必須在您創建的所有線程之間來回切換並給它們一個運行機會)並且用盡OS線程(創建太多或者丟失它們由於他們從未完成任務)會導致性能問題。

3)垃圾收集器已經在它自己的線程(或多線程)。調整GC並避免創建過多的垃圾都是很好的提示。

請參閱Amdahl's Law瞭解有多少線程可以加速任務的限制。 您排除了鎖定問題,但過度鎖定是性能的主要障礙。你做

+0

GC是在自己的線程或線程:) –

+0

和太多的上下文切換也會導致性能問題以及 – Armando

+0

@SleimanJneidi:正確,固定,謝謝 –