2013-07-01 10 views
5

JavaでArrayListを返す共有ライブラリを使用しています。私はそれを反復するので、ConcurrentModificationExceptionがスローされる可能性があり、私は安全であることを100%保証しますか?私は以下のようなことを考えていました。安全でないArrayListを公開するマルチスレッドライブラリ

data_listは、MTライブラリから返されたArrayList <です。

boolean pass = true; 

ArrayList<Something> local = new ArrayList<Something>(256); 

for (int spin=0; spin<10; ++spin) 
{ 
    try { 
    local.addAll(data_list); 
    } 
    catch (java.util.ConcurrentModificationException ce) { 
    pass = false; 
    } 
    finally { 
    if (pass) break; 
    pass = true; 
    } 
} 

私はローカルで動作するべきか、passtrueある変数と仮定すると?

+5

マルチスレッドライブラリは、非同期コレクションをエクスポーズします。私はあなたの最善の策は別のライブラリに切り替えることだと思います。 –

+2

あなたが尋ねた質問に対する答えではありませんが、あるarraylistを別のarraylistにコピーしている場合は、ソースのサイズと同じではなく、 = new ArrayList <>(data_list.size()); 'の代わりに、256を使用するだけです。 – Jules

+0

@Theodorosに同意します。間違った方法でライブラリを使用しようとしていませんか?これはライブラリ自体のデザインが悪いようです。 – cjstehno

答えて

-2

私は基本的な変更はありませんが、私はそのコードは少し単純化することができると思います:

ArrayList<Something> local = new ArrayList<Something>(256); 

for (int spin=0; spin<10; ++spin) 
{ 
    try { 
    local.addAll(data_list); 
    break; 
    } 
    catch (java.util.ConcurrentModificationException ce) {} 
} 
+0

-1、これは要素の乗算を追加する可能性があります(addAllはアトミックではありません)ので、結果セットに重複要素が残る可能性があります。 –

+0

元のコードに同じ問題があります。 – Jules

+0

ええ、 "それをする方法は、これはありません。 –

0

あなたは安全の意味を正確に定義していない、とどのような種類を指定しません、変更のリストに行われているが、多くの場合、手動でインデックスによってそれを反復することが許容されることができる、すなわち

for (int index = 0; index < data_list.size(); index ++) 
    local.add(data_list.get(index)); 

私はそれを見るようにして、変形の4つの可能な種類は、様々な程度であります受容性:

  • 新しい項目を追加できました。このソリューションは、リストがバッキングリストの拡張をトリガーするのに十分に成長しない限り、このケースでは適切に機能するはずです(そして、指数関数的に減少する周波数で起こるはずですが、最終的に成功するように再試行する必要があります)。
  • 既存のアイテムは変更されることがあります。この解決法は、リストの内容の一貫性のある表示をいつでも提示することはできないが、リストに含まれている項目を表す有用なリストを提供することが保証される。 "安全"。
  • 商品が削除されることがあります。このソリューションがIndexOutOfBoundsExceptionで失敗する可能性はわずかであり、変更されるアイテムと同じ警告が整合性に関して適用されます。
  • 商品はリストの中央に挿入することができます。変更されている項目と同じ警告が適用され、重複した値を取得する危険もあります。付加的なケースからの配列拡張の問題も適用されます。
+0

私は実際にこれが好き、素敵な... – Basixp

9

これを行うには安全な方法はありません。 You should not catch ConcurrentModificationException。このクラスのiteratorおよび反復子のメソッドによって返さ

イテレータはフェイルファストされています。リストが構造的に随時変更されると、反復子は、反復子自体のremove以外の方法で、作成したりする方法、追加された後、イテレーターはConcurrentModificationExceptionをスローします。したがって、同時の変更に直面して、イテレータは、未定義の時間に任意の非決定論的な動作を将来的に危険にさらすのではなく、迅速かつきれいに失敗します。

イテレータのフェイル・ファーストの動作は、一般的に言えば、非同期同時変更の存在下では何の保証もできないため、保証できません。フェイル・ファースト・イテレータは、ベストエフォート型でConcurrentModificationExceptionをスローします。したがって、この例外に依存するプログラムを記述するのは間違いです。イテレータのフェイル・ファーストの動作は、バグの検出にのみ使用する必要があります。

HashMap,even can enter an infinite loop when used this wayなどのコレクションがあります。ここにはan explanation of how it happensがあります。

は、このようにしないでください。これを行う正しい方法はありません。

ライブラリの仕組みを誤解しているか、有能な開発者が作成したライブラリを使用してライブラリを切り替える必要があります。

あなたはどのライブラリを使用していますか?

0

あなたはここで悪い状況に陥っていますが、あなたのソリューションは可能な限り健全だと思います。新しいArrayListはループの中に入り、各失敗後に新しく開始する必要があります。あなたがデータをつかむしようとしているときには時間がかかりますので、あなたは、あなたのArrayList自体を拡張する必要がありますする必要はありません

local = new ArrayList<Something>(data_list); 

:実際には、最善のことは次のようにあなたの「試す」行の外観を作ることであるかもしれませんリストが変更される前にこれは、サイズを設定し、作成し、最小の無駄な努力でそれを埋める必要があります。

ConcurrentModification以外のものをキャッチする必要があるかもしれません。あなたはたぶん難しい方法を学ぶでしょう。または、Throwableをキャッチするだけです。

極端に行きたい場合は、forループ内のコードを独自のスレッドで実行してください。ハングしている場合は、それを強制終了して再起動してください。それはいくつかの仕事を取るだろう。

「スピン」が十分に大きくなるようにすると、これはうまくいくと思います。

関連する問題