[英]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個條目),我需要使用多個線程來相當快地完成這個。
但是我需要每個線程從一個唯一索引開始,這樣就不會有兩個線程迭代在列表的同一部分上。 將有一個100
的batchSize
,因此每個線程將從其startIndex
循環到startIndex + 100
。
有沒有辦法實現這個目標? 請注意,我只在這里執行讀取操作,沒有寫入。 列表中的每個條目只是一個String,它實際上是一個SQL查詢,然后我通過JDBC對DB執行。
如果您只打算讀取List
,而不是改變它,您可以簡單地定義Runnable
以獲取List
和startIndex
作為構造函數參數。 只要沒有線程同時修改它,就沒有同時讀取ArrayList
(即使是相同的索引)的危險。
為了安全起見,請確保將ArrayList
包裝在對Collections.unmodifiableList()
的調用中,並將該 List
傳遞給Runnable
。 這樣您就可以確信線程不會修改后備ArrayList
。
或者,您可以在主線程中構建子列表(使用List.subList()
),這樣您就不需要將startIndex
傳遞給每個線程。 但是,在執行此操作之前,您仍希望使子列表不可修改。 六分之一,另外六分之一。
更好的是使用Guava的ImmutableList
; 它天生就是線程安全的。
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.