2

我有一个集合,我想产生一些线程来对其元素做一些繁重的工作。集合的每个元素都必须被处理一次,并且只处理一次。我想尽可能减少同步,我想出了以下代码:

//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,上面的代码安全吗?如果不是,为什么?

4

2 回答 2

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);

如果您不再需要创建和关闭线程池,它会更短。

于 2013-01-03T19:58:09.660 回答
0

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

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

for-each 在每个线程中创建一个新的迭代器,因此不需要同步。

于 2013-01-04T01:00:36.497 回答