我有一个集合,我想生成一些线程来对其元素做一些繁重的工作。集合的每个元素必须处理且只能处理一次。我想保持同步尽可能少,我想出了以下代码:
//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,上面的代码安全吗?如果不是,为什么?
我根本不会使用同步。
我将有一个循环,将任务添加到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);
如果你不需要创建和关闭线程池,它甚至更短。
我认为最好将myCollection设为final,并将代码更改为
public void run() {
Object obj = null;
for (Object e : myCollection) {
obj = e;
}
for-each在每个线程中创建一个新的迭代器,因此不需要同步。