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 は各 Thread に新しい Iterator を作成するため、同期は必要ありません。

于 2013-01-04T01:00:36.497 に答える