簡體   English   中英

將List Iterator傳遞給Java中的多個線程

[英]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.

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