2013-07-01 18 views
5

ArrayList'i döndüren bir Java'da paylaşılan bir kitaplık kullanıyorum; Ben üzerinde yineleme olarak, bir ConcurrentModificationException atılmış olabilir ve güvenli olması için% 100 (?) garanti arıyorum. Aşağıdaki gibi bir şey üzerinde düşünüyordum ve herhangi bir girdi için minnettarım.Güvenli olmayan ArrayList açığa çıktısını taşıyan çok iş parçacıklı kütüphanesi

Veri_listesi, MT kitaplığından döndürülen ArrayList <> dur.

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; 
    } 
} 

yerel ameliyat gerektiğini, nasıl passtrue olan değişken varsayarsak?

+5

Çok iş parçacıklı bir kitaplık, ortaya çıktıktan sonra değiştirmeyi sürdürdüğü eşzamanlı olmayan bir koleksiyon ortaya çıkarır? Bence en iyi bahisten başka bir kütüphaneye geçmek. –

+2

Sorduğunuz soruya bir cevap değil, ancak bir arraylist diğerine kopyalanıyorsanız, hedefin başlangıç ​​boyutunun sabit değil, yerel kaynak boyutuna eşit olması genellikle daha verimlidir. = new ArrayList <> (data_list.size()); 'sadece 256'yi kullanmak yerine. – Jules

+0

@Theodoros ile aynı fikirdeyim, kütüphaneyi yanlış bir şekilde kullanmaya çalışmadığınızdan emin misiniz? Bu kütüphanenin kendisinin kötü tasarımı gibi görünüyor. – cjstehno

cevap

-2

ben herhangi bir temel değişiklikleri gerektirmeyen, ama bu kod biraz basitleştirilmiş olabilir düşünüyorum:

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, bu elemanlar çoğalır (addAll atomik değildir), böylece sonuç kümesinde yinelenen öğeleri sonlandırabilirsiniz –

+0

Aynı sorun orijinal kodda olsa da. – Jules

+0

Evet, ancak bir "kasa" soruyor "Bunu yapmanın yolu, ve bu değil. –

0

Sen güvende derken, ve belirtmeyen tam olarak ne tanımlamaz ne tür modifikasyon listesine yapılmaktadır, ancak birçok durumda elle indeksi üzerinde yineleme için kabul edilebilir örneğin,

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

bana göre, modifikasyon dört olası türde değişen derecelerde, orada kabul edilebilirlik:

  • Yeni öğeler eklenebilir. Bu çözüm, liste bir destek listesi genişlemesini tetiklemek için yeteri kadar büyüdüğü sürece (ve üssel olarak azalan frekansta olması gerektiği gibi, bu durumda sonuç olarak başarılı olmak için tekrar sağlanacaksa tekrar denenmelidir) bu durum için uygun şekilde çalışmalıdır.
  • Mevcut öğeler değiştirilebilir. Bu çözüm, herhangi bir zamanda listenin içeriğinin tutarlı bir görünümünü sunmayabilir, ancak listenizde yer alan, sizin tanımınıza bağlı olarak kabul edilebilir olan öğelerin temsilcisi olan kullanılabilir bir liste sağlamak garanti edilecektir. "kasa".
  • Öğeler çıkarılabilir. Bu çözümün bir IndexOutOfBoundsException ile başarısız olması için küçük bir şans var ve değiştirilmekte olan eşyalar için aynı uyarı, tutarlılık açısından geçerli olacaktır.
  • Öğeler, listenin ortasına eklenebilir. Değiştirilen öğelerle aynı uyarı geçerli olacaktır ve aynı zamanda çoğaltılan değerler alma tehlikesi de olacaktır. Ekleme durumundan ardışık dizi genişletme ile ilgili sorunlar da geçerli olacaktır.
+0

Aslında bunu seviyorum, güzel ... – Basixp

9

Bunu yapmanın güvenli bir yolu yoktur. You should not catch ConcurrentModificationException. Bu sınıfın yineleyici ve listIterator yöntemlerle döndü

yineleyiciler başarısız hızlı gibidir: Liste yapısal herhangi bir zamanda değiştirilirse yineleyici yineleyici kendi kaldır kullanma dışında herhangi bir şekilde, oluşturulan veya yöntemlerini ekleyebilirsiniz sonra Yineleyici bir ConcurrentModificationException atar. Bu nedenle, eşzamanlı modifikasyon karşısında, iteratör, gelecekte belirsiz bir zamanda keyfi, deterministik olmayan davranışları riske atmak yerine, hızlı ve temiz bir şekilde başarısız olur.

Yineleyici eşzamanlı modifikasyon varlığında herhangi bir sert garantinin yapılmasının imkansız olduğu, yineleyicinin başarısızlık davranışının garanti edilemeyeceğine dikkat edin. Başarısız hızlı yineleyiciler, ConcurrentModificationException'ı en iyi şekilde kullanırlar. Bu nedenle, bu özel duruma bağlı bir programın doğruluğu için yazılması yanlış olur: yineleyicilerin başarısız-hızlı davranışı yalnızca hataların algılanması için kullanılmalıdır.

HashMap, even can enter an infinite loop when used this way gibi bazı koleksiyonlar. İşte an explanation of how it happens.

siz bunu yapmamalısınız. Bunu yapmak için doğru bir yol yoktur.

Kitaplığın nasıl çalıştığını ya da kitaplığınızı yetkili bir geliştirici tarafından yazılan bir kitapla değiştirmeniz gerektiğini anlıyorsunuz.

Hangi kütüphaneyi kullanıyorsunuz?

0

Burada kötü bir durumunuz var, ama çözümün olabildiğince sağlam olduğunu düşünüyorum. Yeni ArrayList döngüye girmeli, böylece her başarısızlıktan sonra yeniden başlarsınız. Bu verileri kapmak için çalışıyoruz zaman alacaktır, çünkü senin ArrayList istemiyoruz

local = new ArrayList<Something>(data_list); 

kendisini genişletmek zorunda: Aslında en iyi şey gibi "dene" satırı bakmak yapmak olabilir liste değişmeden önce. Bu, boyutu ayarlamalı, oluşturmalı ve en az boşa harcanan çaba ile doldurmalıdır.

ConcurrentModification'dan başka şeyler yakalamanız gerekebilir. Muhtemelen zor yoldan öğreneceksiniz. Ya da sadece Throwable'ı yakala.

Aşırılara gitmek istiyorsanız, kendi iş parçacığı içinde for döngüsünün içindeki kodu çalıştırın, böylece askıda kalırsa onu öldürebilir ve yeniden başlatabilirsiniz. Bu biraz iş alacak.

"Spin" in yeterince büyük olmasına izin verirseniz, bunun işe yarayacağını düşünüyorum.

İlgili konular