如何在Java中同时处理Collection中的元素

时间:2013-02-08 08:26:12

标签: java collections concurrency

我需要同时处理某些Collection实例中的元素。 换句话说,而不是迭代Collection实例

for (Someclass elem : coll){
     process(elem);
}

我想同时处理这些元素。比方说,像ConcurrentCollectionExecutor(coll, new Callable{…}, numberOfThreads)。此外,应修复多个同时线程。

任何灵活的模式已经存在?

4 个答案:

答案 0 :(得分:8)

将进程方法设置为名为MyRunnable的类中的run()方法,该类实现Runnable,其构造函数将elem作为输入并将其存储为实例变量。然后使用:

ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
for (Someclass elem : coll){
   Runnable worker = new MyRunnable(elem);
   executor.execute(worker);
}

答案 1 :(得分:8)

一个好的解决方案是:

  1. 实例化包含要处理的元素的ArrayBlockingQueue
  2. 实例化ExecutorService以同时执行您的处理
  3. 实例化Runnable,为他们提供ArrayBlockingQueue作为参数
  4. 实现run方法:当队列中有元素时,轮询它们并处理它们
  5. 将您的Runnable提交至ExecutorService
  6. 代码:

    BlockingQueue<Someclass> toProcess = 
        new ArrayBlockingQueue<Someclass>(coll.size(), false, coll);
    ExecutorService es = Executors.newFixedThreadPool(numberOfThreads);
    for(int count = 0 ; count < numberOfThreads ; ++c) {
        es.submit(new MyRunnable(toProcess));
    }
    
    
    private static class MyRunnable() implements Runnable {
        private final BlockingQueue<Someclass> toProcess;
    
        public MyRunnable(BlockingQueue<Someclass> toProcess) {
            this.toProcess = toProcess;
        }
    
        @Override
        public void run() {
            Someclass element = null;
            while((element = toProcess.poll()) != null) {
                process(element);
            }
        }
    }
    

答案 2 :(得分:2)

在此类执行者类的“手工制作”版本之下。请注意,您必须在那里传递Callable(或Runnable)的实例,而不是此类处理器类的类名。

public class ConcurrentCollectionExecutor<T> {

private Collection<T> collection;
private Class<Runnable> processor;
private int numberOfThreads;
private Executor executor;

public ConcurrentCollectionExecutor(Collection<T> collection, Class<Runnable> processor, int numberOfThreads) {
    this.collection = collection;
    this.processor = processor;
    this.numberOfThreads = numberOfThreads;
    this.executor = Executors.newFixedThreadPool(numberOfThreads);
}

public void run() {
    try {
        Constructor<Runnable> constructor = null;
        for (T t : collection) {
            if (constructor == null) {
                constructor = processor.getConstructor(t.getClass());
            }
            executor.execute(constructor.newInstance(t));
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}      
}

答案 3 :(得分:0)

我不知道任何模式,但作为一个想法,你可以在线程数上分配你的集合元素,所以每个线程都有X个元素来处理,例如:

Collection有20个元素,youc你的所有函数提供4个Threads然后实习你启动它们:

thread1 gets the elements [0 .. 4]
thread2 gets the elements [5 .. 9]
thread3 gets the elements [10 .. 14]
thread1 gets the elements [15 .. 19]

请注意,从集合中删除元素可能会导致问题,特别是线程4尝试访问元素[19],而集合中的元素少于20个。

修改

正如大脑提到的,取决于元素处理时间,这个想法可能没有效果,好像处理前5个元素中的一个花了10秒但其他元素只用了0.5秒然后thread1会忙,但其他线程会最终没有并行运行很长时间。