2015-06-20 18 views
6

我是新來的這個併發編程在Java中,並提出了以下情況下,我越來越混亂使用時。

方案1:在下面的代碼我試圖通過調用。開始()上GPSService類,這是一個Runnable實施運行的線程。在Java中同時運行線程中ExecutorService的執行和thread.run之間的區別是什麼?

int clientNumber = 0; 
ServerSocket listener = new ServerSocket(port); 

while (true) { 
      new GPSService(listener.accept(), clientNumber++, serverUrl).start(); 
} 

方案2:在下面的代碼,我嘗試使用的ExecutorService類運行的線程,如圖

int clientNumber = 0; 
ServerSocket listener = new ServerSocket(port); 
while(true) { 
     ExecutorService executor = Executors.newSingleThreadExecutor(); 
     executor.execute(new GPSService(listener.accept(), client++, serverUrl)); 

     executor.shutdown(); 
     while (!executor.awaitTermination(1, TimeUnit.SECONDS)) { 
      // Threads are still running 
      System.out.println("Thread is still running"); 
     } 
     // All threads are completed 
     System.out.println("\nThread completed it's execution and terminated successfully\n");    
} 

我的問題是
這是調用線程的最佳實踐併發編程?
什麼是結果(麻煩)當我第一次或第二次使用時,我會最終結束?
注意:我一直在面對第一種情況,即每隔幾天後程序被吊死的問題。那麼,當我使用第一種方法時,這個問題是否與預期相關?
任何好的/有益的答案將不勝感激:)謝謝

+0

可能重複http://stackoverflow.com/questions/2049948/thread-pool-vs-thread -spawning) –

+0

@NarendraPathai我更具體到我的問題,如果是的話,你怎麼能把它標記爲重複? –

+0

@NarendraPathai我剛剛提到過,只是爲了澄清FirstScenario是否有可能導致此類問題。爲了您的理解,我沒有要求解決這個懸而未決的問題。並感謝您的參考 –

回答

3

您發佈的兩種情況沒有什麼大的區別,除了在Scenario2中管理線程終止;您總是爲每個傳入請求創建一個新線程。如果你想使用ThreadPool,我的建議不是爲每個請求創建一個,而是爲每個服務器創建一個並重用線程。例如:

public class YourClass { 

//in init method or constructor 
ExecutorService executor = Executors....;// choose from newCachedThreadPool() or newFixedThreadPool(int nThreads) or some custom option 


int clientNumber = 0; 
ServerSocket listener = new ServerSocket(port); 
while(true) { 

    executor.execute(new GPSService(listener.accept(), client++, serverUrl)); 

} 

這將允許您使用線程池並控制要爲您的服務器使用多少個線程。如果你想使用Executor,這是首選的方法。

使用服務器池,您需要確定池中有多少個線程;您有不同的選擇,但您可以啓動或使用固定數量或線程,或者嘗試使用非忙線程的池,並且如果所有線程都忙,則會創建一個新線程(newCachedThreadPool())。要分配的線程數量取決於許多因素:併發請求的數量和持續時間。您的服務器端代碼越多,您需要的額外線程就越多。如果您的服務器端代碼速度非常快,則池可以回收已分配的線程的可能性非常高(因爲請求並不是完全在相同的瞬間)。

例如說你在一秒鐘內有10個請求,每個請求持續0.2秒;如果請求到達0,0.1,0.2,0.3,0.4,0.5,...部分秒(例如23/06/2015 7:16:00:00,23/06/2015 7:16:00: 01,23/06/2015 7:16:00:02)你只需要三個線程,因爲來自0.3的請求可以由服務器第一個請求(0爲一個)的線程執行,等等(請求在0.4時間可以重用用於0.1的請求的線程)。由三個線程管理的十個請求。

我建議你(如果你沒有它已經)來讀取Java併發實踐(任務執行的第6章);這是一本關於如何在Java中構建併發應用程序的優秀書籍。

+0

因此,如果我使用newCachedThreadPool()或newFixedThreadPool(int nThreads),因爲我從數百個客戶端每四秒鐘獲取數據,如果我不會以任何問題結束爲每個客戶使用單線程? –

+1

如果您設法正確調整池的大小,使用newCachedThreadPool()不會有任何問題,甚至不會在線程數上設置上限 – Giovanni

1

從Oracle documentationExecutors

public static ExecutorService newCachedThreadPool() 

創建一個創建新線程需要的,但可用時將重用以前構造的線程的線程池。這些池通常會提高執行許多短暫異步任務的程序的性能。

調用執行將重用以前構造的線程(如果可用)。如果沒有現有線程可用,則會創建一個新線程並將其添加到池中。未使用六十秒的線程將被終止並從緩存中移除。

因此,保持閒置時間足夠長的池不會消耗任何資源。請注意,使用ThreadPoolExecutor構造函數可以創建具有類似屬性但具有不同細節的池(例如,超時參數)。

public static ExecutorService newFixedThreadPool(int nThreads) 

創建一個可重用不受限制的隊列操作線程的固定數目的線程池。在任何時候,最多nThreads線程都將被激活處理任務。如果在所有線程處於活動狀態時提交其他任務,則它們將在隊列中等待,直到線程可用。

如果任何線程在關閉之前的執行期間由於失敗而終止,那麼如果執行後續任務需要新的線程將取代它。池中的線程將一直存在,直到它被明確關閉。

@Giovanni是說,你不必須提供的線程數來newCachedThreadPool不像newFixedThreadPool(),在那裏你必須通過對線程池的線程數最高上限。

但是在這兩者之間,newFixedThreadPool()是優選的。 newCachedThread Pool可能會導致泄漏,並且由於無限性質,您可能會達到可用線程的最大數量。有些人認爲這是一種邪惡。

看一看相關SE問題:

Why is an ExecutorService created via newCachedThreadPool evil?

[線程池VS主題產卵(的
+0

使用newFixedThreadPool()時如何確定線程使用的數字。 – Jesse

+0

從Runtime.getRuntime()開始。availableProcessors() –

相關問題