簡體   English   中英

如何在Java中使用多個線程迭代一個Collection,其中沒有兩個線程迭代在Collection的同一部分?

[英]How to use multiple threads in Java to iterate over a Collection where no two threads ever iterate over the same part of the Collection?

我需要迭代一個大的ArrayList (~50,000個條目),我需要使用多個線程來相當快地完成這個。

但是我需要每個線程從一個唯一索引開始,這樣就不會有兩個線程迭代在列表的同一部分上。 將有一個100batchSize ,因此每個線程將從其startIndex循環到startIndex + 100

有沒有辦法實現這個目標? 請注意,我只在這里執行讀取操作,沒有寫入。 列表中的每個條目只是一個String,它實際上是一個SQL查詢,然后我通過JDBC對DB執行。

如果您只打算讀取List ,而不是改變它,您可以簡單地定義Runnable以獲取ListstartIndex作為構造函數參數。 只要沒有線程同時修改它,就沒有同時讀取ArrayList (即使是相同的索引)的危險。

為了安全起見,請確保將ArrayList包裝在對Collections.unmodifiableList()的調用中,並將 List傳遞給Runnable 這樣您就可以確信線程不會修改后備ArrayList

或者,您可以在主線程中構建子列表(使用List.subList() ),這樣您就不需要將startIndex傳遞給每個線程。 但是,在執行此操作之前,您仍希望使子列表不可修改。 六分之一,另外六分之一。

更好的是使用GuavaImmutableList ; 它天生就是線程安全的。

Java 8中也有並行流 ,但要注意這個解決方案; 他們很強大,但很容易出錯。

如果您使用Java 8,請查看list.stream().parallel()

對於Java 7,使用線程外部的subList()將工作拆分為多個部分。 然后,線程應該只在這樣的子列表上運行。 對於大多數列表, subList()是一種非常有效的操作,不會復制數據。 如果修改了支持列表,則會收到ConcurrentModificationException

在將數據提供給線程時,我建議查看Executor API和Queue 只需將所有工件放入隊列中,然后讓執行者解決所有問題。

有一個原子變量:

int nextBatch = 0;

每次線程包含新批次時增加它:

public synchronized int getNextBatch() {
    nextBatch += batchSize;
    if(nextBatch >= arraylist.size()) {
        // The end was reached
        return -1;
    }
    return nextBatch;
}

線程將調用此方法並獲取我們需要處理的范圍:

int start = getNextBatch();
if(start == -1) {
    // The end was reached
}
int end = Math.min(start + batchSize, arraylist.size);

// Iterate over its own range
for(int i = start; i < end; i++) {
    Object obj = arraylist.get(i);
    // Do something with obj
} 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM