2008-10-16 23 views
7

Birden çok iş parçacığı tarafından erişilen bir Liste nesnesine sahibim. Çoğunlukla bir iş parçacığı vardır ve bazı durumlarda listeyi güncelleyen iki iş parçacığı vardır. İşlenmekte olan kullanıcı isteklerinin sayısına bağlı olarak bu listeden okuyabilen bir veya beş iş parçacığı vardır. Liste, gerçekleştirilecek görevlerin sırası değil, aynı anda alınabilen ve güncelleştirilen etki alanı nesneleri listesidir.
-kullanır senkronize blok Normal Lock -kullanır
(yani okuma ve yazma ops paylaşan aynı kilidi)
-kullanır ReadWriteLock:Eşzamanlı olarak erişilen bir Liste için Java 6'da kullanılacak en iyi yaklaşım

Şimdi bu listeye evreli erişim yapmak için çeşitli yolları vardır yeni ConcurrentBLABLBA toplama sınıfların
-kullanır bir

sorum:
Cricital bölümlerin tipik olarak çok sayıda işlem içermediğinden (çoğunlukla yalnızca listeye ekleme/çıkarma/ekleme veya öğe alma) göz önüne alındığında en uygun yaklaşım nedir?
Yukarıda listelenmeyen başka bir yaklaşım önerebilir misiniz? değil Sıralanmış liste (yani kullanılarak sıralanır olmasa

Bazı kısıtlar
-optimal performans kritiktir, bellek kullanımı çok değil
-it, sıralı bir liste (şu anda bir ArrayList'in üzerinde senkronize) olması gerekir Karşılaştırılabilir veya Karşılaştırıcı, ancak ekleme sırasına göre)
-liste 100000'e kadar etki alanı nesnesi içeren büyük olacaktır, bu nedenle CopyOnWriteArrayList gibi uygun bir şey kullanamaz
- yazma/güncelleştirme bölümleri genellikle çok hızlıdır, basit bir ekleme yapar/kaldır/ekle veya değiştir (set)
-kullanım işlemleri çoğunlukla bir elementAt (index) çağrısı yapar, bazı okuma işlemleri bir ikili arama yapabilir, ya da indexOf (element)
-no doğrudan iterasyon liste üzerinden yapılır; indexOf (..) liste geçecek

cevap

3

Sıralı bir liste kullanmanız gerekiyor mu? Harita tipi bir yapı daha uygunsa, ConcurrentHashMap kullanabilirsiniz. Bir liste ile, bir ReadWriteLock muhtemelen en etkili yoldur.

OP'in düzenlemesini yansıtmak için düzenle: Ekleme siparişinde ikili arama? Bir zaman damgasını depolar ve karşılaştırma için bunu ikili aramanızda mı kullanırsınız? Öyleyse, zaman damgasını anahtar olarak ve kapsayıcı olarak (anahtar sırasını koruyan) ConcurrentSkipListMap kullanabilirsiniz.

+0

ConcurrentSkipListMap fikrini beğeniyorum. Zamanın% 90'ında liste, bazı zaman damgalarına (her alanın kimliğinin bir kısmına) göre sıralanır, bu yüzden muhtemelen bunun için optimizasyona değer. Hala diğer% 10'u düşünecek. –

1

Okuma konuları neler yapıyor? Listede yineleme yapıyorlarsa, gerçekten yineleme işleminin tamamı boyunca listeye dokunmadığından emin olmanız gerekir, aksi halde çok tuhaf sonuçlar alabilirsiniz.

İhtiyaç duyduğunuz semantiği tam olarak tanımlayabiliyorsanız, sorunu çözmeniz mümkün olmalıdır; ancak, doğru ve verimli bir şekilde yapmak için kendi koleksiyonunuzu yazmanız gerektiğini de görebilirsiniz. Alternatif olarak, CopyOnWriteArrayList da yeterince iyi olabilir - potansiyel olarak pahalıysa. Temel olarak, gereksinimlerinizi ne kadar çok bağlayabilirsiniz, o kadar verimli olabilir.

+0

CopyOnWriteArrayList'e bir göz attım, ancak bu kullanımı çok pahalı olurdu. Liste, potansiyel olarak 100000 öğeye sahip olabilir ve çok fazla güncellenir. –

+2

Tamam, bu durumda anlambiliminizi gerçekten dikkatli bir şekilde çalışmanız gerekecek. Bu güncellemeler ekleme/silme yapmak mı yoksa sadece öğeleri mi değiştiriyor? Ekliyor/siliyorlarsa, listenin başında/kuyruğunda mı yapıyorlar? (Bu durumda bağlantılı bir liste size gerçekten yardımcı olabilir.) –

1

bu sorun için bir doktorunun çözümdür ama eğer bilmiyorum ... o verinin o büyük miktarda tutmak için bir veritabanı yöneticisini kullanın ve

+0

Veriler sunucu tarafında DB yöneticisi ve Appserver katmanı tarafından yönetiliyor, ancak bir şekilde son kullanıcıya göstermemiz gerekiyor.Bu listenin yöneticisi, verilerin alındığı istemci tarafında gerçekleşir. –

1

Ben işlemlerini yönetmesine izin vermek için bana mantıklı Bir veritabanının ikinci Telcontar's suggestion numaralı sürümü, aslında bu veri ölçeğini yönetmek ve iş parçacıkları arasında görüşme yapmak için tasarlandığından, bellek içi koleksiyonlar olmadığından.

Verilerin sunucudaki bir veritabanında olduğunu ve istemcilerdeki yerel listenin kullanıcı arabirimi uğruna olduğunu söylüyorsunuz. İstemcideki tüm 100000 öğeyi bir kerede saklamanız veya üzerinde karmaşık düzenlemeler yapmanız gerekmemelidir. Bana öyle geliyor ki, istemcide istediğiniz şey veritabanına hafif bir önbellek.

Yalnızca istemcideki geçerli veri alt kümesini bir kerede depolayan bir önbellek yazın. Bu istemci önbelleği, kendi verileri üzerinde karmaşık çok iş parçacıklı düzenlemeler gerçekleştirmez; bunun yerine, tüm düzenlemeleri sunucuya besler ve güncelleştirmeleri dinler. Veriler sunucuda değiştiğinde, istemci sadece eski verileri ve eski verileri unutur ve tekrar yükler. Koleksiyonun kendisinin sadece bir atanmış ipliği okumasına veya yazmasına izin verilir. Bu şekilde istemci, karmaşık düzenlemelere gerek kalmadan sunucu üzerinde gerçekleşen düzenlemeleri basitçe yansıtır.

Evet, bu oldukça karmaşık bir çözümdür. bunun bileşenleri şunlardır:

    oldukça şeyi
  • değişti verilerin
  • bir önbellek sınıfı hakkında güncellemeler almak için bir protokol yerine, ürün 478712 için 478901 veri aralığı yüklenmesi için bir protokol söylemek
  • Bu, öğeleri sunucudaki bilinen dizine göre depolar
  • Sunucuyla iletişim kuran bu önbelleğe ait bir iş parçacığı. Bu koleksiyon kendisi yazar tek iplik
  • veri
  • o yüklendiğinde UI bileşenleri bunları veri alma için izin uygulamak bir arayüz alındığında geri aramalar işleyen bu cache ait bir iş parçacığı
ilk bıçak başta

, bu önbellek kemikleri şöyle görünebilir: belli ki, kendiniz için doldurmak gerekecek detay çok şey var

class ServerCacheViewThingy { 
    private static final int ACCEPTABLE_SIZE = 500; 
    private int viewStart, viewLength; 
    final Map<Integer, Record> items 
      = new HashMap<Integer, Record>(1000); 
    final ConcurrentLinkedQueue<Callback> callbackQueue 
      = new ConcurrentLinkedQueue<Callback>(); 

    public void getRecords (int start, int length, ViewReciever reciever) { 
     // remember the current view, to prevent records within 
     // this view from being accidentally pruned. 
     viewStart = start; 
     viewLenght = length; 

     // if the selected area is not already loaded, send a request 
     // to load that area 
     if (!rangeLoaded(start, length)) 
      addLoadRequest(start, length); 

     // add the reciever to the queue, so it will be processed 
     // when the data has arrived 
     if (reciever != null) 
      callbackQueue.add(new Callback(start, length, reciever)); 
    } 

    class Callback { 
     int start; 
     int length; 
     ViewReciever reciever; 
     ... 
    } 

    class EditorThread extends Thread { 

     private void prune() { 
      if (items.size() <= ACCEPTABLE_SIZE) 
       return; 
      for (Map.Entry<Integer, Record> entry : items.entrySet()) { 
       int position = entry.key(); 
       // if the position is outside the current view, 
       // remove that item from the cache 
       ... 
      } 
     } 

     private void markDirty (int from) { ... } 

     .... 
    } 

    class CallbackThread extends Thread { 
     public void notifyCallback (Callback callback); 
     private void processCallback (Callback) { 
      readRecords 
     } 
    } 
} 

interface ViewReciever { 
    void recieveData (int viewStart, Record[] records); 
    void recieveTimeout(); 
} 

.

import java.util.Collections; 
import java.util.ArrayList; 

ArrayList list = new ArrayList(); 
List syncList = Collections.synchronizedList(list); 

// make sure you only use syncList for your future calls... 

Bu kolay bir çözümdür:

+0

Cevabınız için teşekkür ederiz. En fazla 100000 ürün, müşteriye ulaştığımız verilerin "sayfası" dır. DB, milyarlarca giriş içerebilir. Ciddiyetle değerlendirdiğim şey, listeye yalnızca bir iş parçacığıyla erişme tavsiyenizdir. Bu kesinlikle bir şeyleri basitleştirecektir. –

1

Sen senkronizasyon uygulayan bir sarmalayıcı kullanabilirsiniz. Daha karmaşık çözümlere başvurmadan önce bunu denemeliyim.

İlgili konular