【问题标题】:Is this multithreaded iteration safe?这种多线程迭代安全吗?
【发布时间】:2012-12-18 05:53:07
【问题描述】:

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

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

【问题讨论】:

  • 只要注释 1 保持正确就可以了。不过,执行者绝对是解决此类问题的方法。
  • 如果您出于性能原因尝试将synchronized 块保持较小,那么您可能会惊讶于在创建和执行每个(本机)线程期间花费了多少时间,请按照建议使用执行程序.
  • 您的概念代码看起来不错。应该很好用。对迭代器的访问(包括检查和读取对象)是同步的,所以没有问题。

标签: java multithreading iterator


【解决方案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 不更改,它会起作用。
【解决方案2】:

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

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

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

【讨论】:

  • hmmm... 使用此代码,每个线程将对集合中的每个对象执行操作,而我只需要对每个对象进行一次操作。此外,增强的 for 循环在内部使用迭代器(它应该同时调用 hasNext() 和 next()),如果不同步,代码可能会中断。
  • 为每个线程创建一个迭代器,我认为这不是一个好主意。这是一种资源的浪费,带来了很多开销。
猜你喜欢
  • 2013-02-20
  • 1970-01-01
  • 2014-03-18
  • 2011-04-15
  • 2011-08-02
  • 1970-01-01
  • 1970-01-01
  • 2014-12-12
  • 1970-01-01
相关资源
最近更新 更多