65

事前に入力された配列リストがあります。そして、配列リストから要素を削除する複数のスレッドがあります。各スレッドは以下のremoveメソッドを呼び出し、リストから1つのアイテムを削除します。次のコードは私に一貫した振る舞いを与えますか?

ArrayList<String> list = Collections.synchronizedList(new ArrayList<String>());

void remove(String item)
{
     do something; (doesn't work on the list)
     list.remove(item);
}

ありがとう!

4

7 に答える 7

71

はい、リストを反復処理する場合は注意が必要です。この場合、リストを同期する必要があるためです。Javadocから:

返されたリストを反復処理するときは、ユーザーが手動でリストを同期する必要があります。

List list = Collections.synchronizedList(new ArrayList());
    ...
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

または、CopyOnWriteArrayList書き込みには時間がかかりますが、この問題がないものを使用できます。

于 2012-07-06T10:32:46.953 に答える
24

「remove」メソッドがアトミックである必要がない限り、これで問題ありません。

つまり、たとえば「何かをする」でアイテムがリストに複数回表示されていることを確認した場合、次の行に到達するまでにその確認の結果が間違っている可能性があります。

また、反復するときは、リストで同期していることを確認してください。

synchronized(list) {
    for (Object o : list) {}
}

Peter Lawreyが述べたように、CopyOnWriteArrayListを使用すると、作業が楽になり、並行性の高い環境でパフォーマンスが向上します。

于 2012-07-06T10:32:08.970 に答える
12

Collections#synchronizedList(List)javadocから

指定されたリストに基づく同期(スレッドセーフ)リストを返します。シリアルアクセスを保証するために 、バッキングリストへのすべてのアクセスが返されたリストを介して行われることが重要です...ユーザーがリストを反復処理するときに、返されたリストを手動で同期することが不可欠です。このアドバイスに従わないと、非決定論的な動作が発生する可能性があります。

于 2012-07-06T10:34:57.893 に答える
3

リストには2つの異なる問題があります:
1)モノスレッド環境であっても反復内で変更を行うと、次の例のようにConcurrentModificationExceptionが発生します:

List<String> list = new ArrayList<String>();
for (int i=0;i<5;i++)
   list.add("Hello "+i);

for(String msg:list)
   list.remove(msg);

したがって、この問題を回避するには、次のようにします。

for(int i=list.size()-1;i>=0;i--)
   list.remove(i);

2)2番目の問題は、マルチスレッド環境である可能性があります。上記のように、synchronized(list)を使用して例外を回避できます。

于 2012-10-31T20:59:29.037 に答える
0

はい、synchronizedリストがあるので問題なく動作します。を使用することをお勧めしますCopyOnWriteArrayList

CopyOnWriteArrayList<String> cpList=new CopyOnWriteArrayList<String>(new ArrayList<String>());

    void remove(String item)
    {
         do something; (doesn't work on the list)
                 cpList..remove(item);
    }
于 2012-07-06T10:45:14.243 に答える
0

これにより、追加/削除操作の動作が一貫します。ただし、反復中は明示的に同期する必要があります。このリンクを参照してください

于 2012-07-06T10:37:42.880 に答える
-6
synchronized(list) {
    for (Object o : list) {}
}
于 2014-05-22T07:50:32.807 に答える