2012-07-23 124 views
1

我正在開發一個程序,可以發送http請求來獲取文件。 我有填充隊列所有請求事項:我很困惑Java多線程

Queue<RequestItem> requestItems = buildRequest4Docs(); 

然後,

int threadNum = requestItems.size(); 
     //ExecutorService exs = Executors.newFixedThreadPool(threadNum); 

     for (int i = 0; i < threadNum; i++) { 
      ResponseInterface response = new CMSGOResponse(); 
      RequestTask task = new RequestTask(requestItems.poll(), this, response); 
      task.run(); 
      //exs.execute(new RequestTask(requestItems.poll(), this, response)); 
     } 
     //exs.shutdown(); 

我很困惑在這裏,在for循環,確實任務同時運行或任務的運行呢?一?

謝謝!

+0

類 「RequestTask」 實現 「可運行」 – zxi 2012-07-23 09:18:13

回答

4

在你得到它現在的任務也將被逐一執行的方式。如果您取消註釋了您現在獲得的代碼作爲註釋並對行RequestTask task = new RequestTask(requestItems.poll(), this, response);task.run();進行註釋,您將獲得併發執行。

所以對於併發執行它看起來像這樣:

int threadNum = requestItems.size(); 
ExecutorService exs = Executors.newFixedThreadPool(threadNum); 

for (int i = 0; i < threadNum; i++) { 
    ResponseInterface response = new CMSGOResponse(); 
    exs.execute(new RequestTask(requestItems.poll(), this, response)); 
} 
exs.shutdown(); 
while (! exs.isTerminated()) { 
    try { 
     exs.awaitTermination(1L, TimeUnit.DAYS); 
    } 
    catch (InterruptedException e) { 
     // you may or may not care here, but if you truly want to 
     // wait for the pool to shutdown, just ignore the exception 
     // otherwise you'll have to deal with the exception and 
     // make a decision to drop out of the loop or something else. 
    } 
} 

除此之外,我建議,你不綁定與ExecutorService創建任務的你有量線程數量上班。將它連接到主機系統的處理器數量通常是更好的方法。要獲得處理器的使用量:Runtime.getRuntime().availableProcessors()

而在執行器服務中,像這樣初始化您放置隊列中的項目。但是,很好地工作,而不會提取總大小,而是輪詢Queue,直到它不返回其他數據。

我的建議最後的結果看起來是這樣的:

final int threadNum = Runtime.getRuntime().availableProcessors(); 
final ExecutorService exs = Executors.newFixedThreadPool(threadNum); 

while (true) { 
    final RequestItem requestItem = requestItems.poll(); 
    if (requestItem == null) { 
     break; 
    } 
    final ResponseInterface response = new CMSGOResponse(); 
    exs.execute(new RequestTask(requestItem , this, response)); 
} 
exs.shutdown(); 
+0

我建議ExecutorService池大小配置比上面更復雜。我會根據他們正在做的事情以及他們的資源約束來配置線程的數量,而不僅僅是CPU的數量(例如,如果RequestTask正在查詢遠程服務會發生什麼) – 2012-07-23 09:21:06

+0

這取決於預期的任務數量。但是,將線程數量設置爲任務數量是一個糟糕的主意。如果現在有1000個任務在等待,會發生什麼?在這種情況下可能會發生問題。上面的方法是可行的,它不會是最有效的方法,因爲線程的構建通常非常昂貴。如果你想要一個非常有效的解決方案,你必須將線程數量擴展到任務數量和處理器數量。如果只有幾項任務,你也必須考慮不使用線程。 – Nitram 2012-07-23 09:25:26

+0

如果有10個任務和2個CPU,在上面的代碼中,10個任務如何分配給2個線程?在每個線程中,任務是否按順序運行?我的意思是,如果java能夠自動地將任務安排到空閒線程?@Nitram – zxi 2012-07-23 10:00:55

1

您正在當前線程中逐一運行它們。您需要使用ExecutorService來同時運行它們。

4

我很困惑,在for循環中,任務是同時運行還是一個一個的運行?

隨着你發佈的代碼,他們會運行一個接一個,因爲(假設RequestTaskThread一個子類)你叫run您應該致電start現在你已經說過RequestTask implements Runnable,正確的代碼不會調用start(它沒有!),而是new Thread(task);(但它看起來像你現在已經收到關於ExecutorService,這是另一種方式來做到這一個很好的答案。)

假設你電話start啓動它們在不同的線程,而不是,那麼是的,他們」都會並行運行(儘可能在硬件上運行等)。

2

目前正在運行的線程的順序,那麼你有兩種方式來運行的線程(假設RequestTask繼承Thread)

I.Either創建線程對象,並調用start()方法。

RequestTask task = new RequestTask(requestItems.poll(), this, response); 
task.start(); // run() method will be called, you don't need to call it 

II.Or創建的ExecutorService

ExecutorService pool = Executors.newFixedThreadPool(poolSize); 
//.... 
for (int i = 0; i < threadNum; i++) { 
    ResponseInterface response = new CMSGOResponse(); 
    RequestTask task = new RequestTask(requestItems.poll(), this, response); 
    pool.execute(task); 
} 
1
I am confused here, in the for loop,does the tasks run simultaneously? Or the tasks run one by one? 

任務將在同一個線程即one by one因爲你調用run()寧可start執行,也不會運行任務在新線程中。

 int threadNum = requestItems.size(); 
     ExecutorService exs = Executors.newFixedThreadPool(threadNum); 


     ResponseInterface response = new CMSGOResponse(); 
     RequestTask task = new RequestTask(requestItems.poll(), this, response); 

     exs.execute(task);   
     exs.shutdown(); 

在上述情況下,任務將在新的線程中執行,並儘快分配10個不同的任務ExecutorService他們將在不同的線程異步執行。

0

我通常傾向於創建我的線程(或實現接口的類),然後使用start()方法啓動它們。

在你的情況下,由於RequestTask實現Runnable,您可以添加這樣的start()方法:

public class RequestTask implements Runnable { 
    Thread t; 
    boolean running; 

    public RequestTask() { 
     t = new Thread(this); 
    } 

    public void start() { 
     running = true; // you could use a setter 
     t.start(); 
    } 

    public void run() { 
     while (running) { 
      // your code goes here 
     } 
    } 
} 

,則:

int threadNum = requestItems.size(); 
RequestTask[] rta = new RequestTask[threadNum]; 

// Create the so-called Threads ... 
for (int i=0;i<threadNum;i++) { 
    rta[i] = new RequestTask(requestItems.poll(), this, new CMSGOResponse()); 
} 

// ... THEN launch them 
for (int i=0;i<threadNum;i++) { 
    rta[i].start(); 
}