[英]Passing a List Iterator to multiple Threads in Java
我有一個包含大約200K元素的列表。
我能夠將此列表的迭代器傳遞給多個線程並讓它們遍歷整個批次,而沒有任何訪問相同的元素嗎?
這就是我現在想到的。
主要:
public static void main(String[] args)
{
// Imagine this list has the 200,000 elements.
ArrayList<Integer> list = new ArrayList<Integer>();
// Get the iterator for the list.
Iterator<Integer> i = list.iterator();
// Create MyThread, passing in the iterator for the list.
MyThread threadOne = new MyThread(i);
MyThread threadTwo = new MyThread(i);
MyThread threadThree = new MyThread(i);
// Start the threads.
threadOne.start();
threadTwo.start();
threadThree.start();
}
MyThread的:
public class MyThread extends Thread
{
Iterator<Integer> i;
public MyThread(Iterator<Integer> i)
{
this.i = i;
}
public void run()
{
while (this.i.hasNext()) {
Integer num = this.i.next();
// Do something with num here.
}
}
}
我期望的結果是每個線程每個處理大約66,000個元素,而不會過多地鎖定迭代器,並且沒有任何線程訪問相同的元素。
這聽起來有用嗎?
你真的需要手動操作線程和迭代器嗎? 您可以使用Java 8 Stream
並讓parallel()
完成這項工作。
默認情況下,它將使用少一個線程,因為您有處理器。
示例:
list.stream()
.parallel()
.forEach(this::doSomething)
;
//For example, display the current integer and the current thread number.
public void doSomething(Integer i) {
System.out.println(String.format("%d, %d", i, Thread.currentThread().getId()));
}
結果:
49748, 13
49749, 13
49750, 13
192710, 14
105734, 17
105735, 17
105736, 17
[...]
編輯:如果您使用的是maven,則需要在pom.xml
中添加此配置才能使用Java 8:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
您不能使用單個迭代器以線程安全的方式執行此操作。 我建議使用子列表:
List sub1 = list.subList(0, 100);
List sub2 = list.subList(100, 200);
ArrayList#subList()
方法將只包裝給定的列表而不復制元素。 然后,您可以在不同的線程中迭代每個subList。
由於實現Iterator
接口的類的next()
方法執行數據操作,因此next()
方法的並發使用需要同步。 可以使用迭代器對象上的synchronized塊完成同步,如下所示:
synchronized(i)
{
i.next();
}
但是,如果您只需要並行處理列表,我建議在上面的答案中使用Stream API。
您好,為了防止您的線程從長發綹或飢餓,您可以使用線程池類中的ExecutorService。 對於我來說,這比使用synchronized,lock或Re-entrant-locks更好。 您也可以嘗試使用Fork / join,但我之前沒有使用它。 這是一個示例代碼,但我希望你能得到這個想法
public static void main(String[] args){
ExecutorService executor = Executors.newFixedThreadPool(200000);
List<Future<Integer>> futureList = new ArrayList<>();
//iteration code goes here
executor.shutdown();
}
Public class MyThread implements Callable<ArrayList<Integer>>{
@Override
public Iterator<Integer> call() throws Exception {
//code goes here!
}
}
如果使用並行流,則將跨多個線程執行代碼,並在線程之間均勻分布元素:
list.parallelStream().forEach(this::processInteger);
這種方法使編碼變得非常簡單; 所有繁重的工作都由JRE完成。
另外,關於你的代碼,擴展Thread
是一種糟糕的風格。 相反,實現Runnable
並將實例傳遞給Thread
的構造函數 - 請參閱live
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.