这种多线程迭代是否安全?

时间:2013-01-03 19:54:40

标签: java multithreading iterator

我有一个集合,我想生成一些Threads来对它的元素做一些繁重的工作。集合的每个元素必须只处理一次。我希望尽可能减少同步,我想出了以下代码:

//getting the iterator is actually more complicated in my specific case
final Iterator it = myCollection.terator(); 
Thread[] threads = new Thread[numThreads];

for( int i = 0; i < numThreads; i++ ) {
    threads[i] = new Thread(new Runnable() {
        public void run() {
            Object obj = null;
            while(true) {
                synchronized (it) {
                    if(it.hasNext())
                        obj = it.next();
                    else
                        return;
                }
                //Do stuff with obj
            }
        }
    });
    threads[i].start();
}

for (Thread t : threads)
    try {
        t.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

注意:任何线程都不会通过添加或删除项目来修改集合,而“使用obj进行操作”

这段代码与我在人们倾向于在集合本身上进行同步,使用Collection.synchronizedStuff..或者只是在整个迭代中同步的示例完全不同。在我的研究过程中,我发现可能使用ThreadPoolExecutor实现了更好的替代方案,但让我们暂时忘掉它......

考虑到上面的注释1,上面的代码是否安全?如果没有,为什么?

2 个答案:

答案 0 :(得分:5)

我根本不会使用同步。

我会有一个循环,它将任务添加到ExecutorService。

ExecutorService es = Executors.newFixedThreadPool(nThreads);

for(final MyType mt: myCollection)
    es.submit(new Runnable() {
       public void run() {
           doStuffWith(mt);
       }
    });
es.shutdown();
es.awaitTermination(1, TimeUnit.HOURS);

如果删除创建和关闭线程池的需要,它甚至更短。

答案 1 :(得分:0)

我认为最好将我的Collection设为final并将代码更改为

 public void run() {
       Object obj = null;
       for (Object e : myCollection) {
           obj = e;
       }

for-each在每个Thread中创建一个新的Iterator,因此不需要同步。