2014-11-25 18 views
7

Potrzebuję twojej porady. Na wstępie chciałbym opisać wstępne warunki.Jednoczesna kolekcja do 50/50 odczyt/zapis

  1. mam pewne osoby trzeciej Java obiektów z domyślnie java.lang.Object „s hashCode() i equals() realizacji. Interfejs Comparable nie jest zaimplementowany. Rozmiar jest nieistotny.
  2. Potrzebuję przechowywać takie obiekty przez jakiś czas w pamięci. Będę czytać i pisać je z różnych wątków w stosunku 50/50 (około 50% czyta i 50% pisze).
  3. Kolejność obiektów nie jest ważna. Po prostu chcę mieć możliwość wzięcia jakiegoś przedmiotu ze sklepu, to wszystko. Z bierze mam na myśli zarówno uzyskać i usunąć w tym samym czasie.
  4. Oczywiście, chcę, aby działał tak szybko, jak to możliwe, przy najniższym zużyciu pamięci. Próbuję uniknąć wszelkich synchronizacji w moim kodzie.

Najpierw próbowałem samodzielnie rozwiązać ten problem. Od razu odrzuciłem kolekcje CopyOnWriteArray* ze względu na duże zużycie pamięci. Czytałem, że lepiej używać ich w przypadku rzadkich zapisów. ConcurrentHashMap w ogólnych apartamentach dla moich potrzeb, ale nie znalazłem sposobu, aby podjąć operacji atomowej bez synchronizacji. Zatrzymałem się z moim dochodzeniem w sprawie kolekcji ConcurrentSkipListSet. Zawiera on metodę pollFirst, która jest całkiem niezłym zbiorem dla obiektów z.

Zaimplementowałem moje rozwiązanie z ConcurrentSkipListSet jako podstawę. Wszystko działa dobrze z wyjątkiem jednego małego szczegółu. Jak wspomniałem wyżej obiekty, z którymi pracuję, nie implementuję Comparable. Aby użyć wybranej kolekcji, muszę w jakiś sposób wdrożyć Comparator. Oto moja implementacja tego interfejsu. W tym przykładzie użyłem bezpośrednio java.lang.Object zamiast mojego typu obiektów. Zrobiłem to, ponieważ implementacja jest całkowicie taka sama, różnica jest tylko w ogólnej części klasy.

import java.util.Comparator; 

public class ObjectComparator implements Comparator<Object> { 

    public int compare(Object o1, Object o2) { 
     return o1.hashCode() - o2.hashCode(); 
    } 
} 

Wady tej implementacji są oczywiste. Odkryłem, że jest tam no guarantee, że dwa różne obiekty będą miały różne kody skrótów. W takim przypadku można stracić niektóre przedmioty, które nie są akceptowane. Myślałem, aby zwrócić kilka liczb losowych w przypadku równych kodów mieszania dla różnych obiektów, ale nie jestem pewien, że nie złamie implementacji ConcurrentSkipListSet.

W odniesieniu do opisanej sytuacji mam dwa ogólne pytania.

  1. Czy możliwe jest wdrożenie Comparator dla mojego obiektu w taki sposób, aby jak nie wrócić 0 dla różnych obiektów i zachować ConcurrentSkipListSet funkcjonalności?
  2. Czy istnieje inny sposób przechowywania moich obiektów?

Z góry dziękuję za odpowiedzi.

+0

Jak duże są twoje przedmioty? Strategia CopyOnWrite jest najlepsza, jeśli masz <100 obiektów ze względu na ciężkość semaforu. A jeśli twoje kolekcje nie są zbyt duże, możesz dopasować wszystko do pokolenia Eden za pomocą bardzo wydajnego algorytmu. – Taky

+0

@Taky Rozmiar kolekcji nie został określony. Może to być 100 lub 10k. Nie wiem Próbuję znaleźć jakiś ogólny sposób rozwiązania tego problemu. Również nie złapałem drugiej części twojego komentarza. Co masz na myśli mówiąc o "pokoleniu Eden"? – artspb

+0

Przez "pokolenie Eden" mam na myśli młodą pulę obiektu JVM. – Taky

Odpowiedz

3

Prawdopodobnie szukasz ConcurrentLinkedQueue, to będzie przechowywać elementy w oparciu o zamówienie FiFo (pierwsze weszło). Z tego powodu nie są wymagane wymagania. Implementacja tej kolejki jest bardzo wydajna, bez żadnego wewnętrznego blokowania.

Jedną z trudności, które masz (jeśli nie używasz zamków) jest to, że nie możesz sprawdzić, czy kolekcja nie jest pusta, a następnie wziąć ją (ponieważ mogła ulec zmianie po sprawdzeniu i przed wykonaniem działania). W związku z tym funkcja take powróci null, gdy nic nie będzie obecne. Jeśli nie chcesz utrzymywać odpytywania danych, możesz także skorzystać z klas implementujących interfejs BlockingQueue, który oferuje funkcje, które czekają, aż dane będą dostępne.

1

1: Można zaimplementować porównawczy jako takie:

public int compare(Object o1, Object o2) { 
    if (o1 == o2) { 
     return 0; 
    } else { 
     int dif = o1.hashCode() - o2.hashCode(); 
     if (dif != 0) { 
      return dif; 
     } else { 
      return 1; //Might cause issues 
     } 
    } 
} 

2: Można zrobić każdy normalny kolekcji zsynchronizowane przy użyciu java.util.Collections.synchronizedCollection() (lub dowolna inna metoda zsynchronizowana). Na przykład, jeśli zsynchronizujesz LinkedList, możesz użyć polecenia remove (index) do , aby zabrać obiekt pod obiekt.

+0

1. Wspomniałem o takiej implementacji w moim pytaniu. Jesteś pewien, że nie złamie logiki "ConcurrentSkipListSet"? 2. Tak, to dobra opcja. Ale w przypadku dużej synchronizacji obciążenia doprowadzi do problemów z wydajnością. Próbuję tego uniknąć. – artspb

+0

@Art Hm źle odczytałem informacje o komparatorze. Przypuszczam, że można również umieścić każdy obiekt w opakowaniu Porównywalne z indeksem opartym na kolejności, w jakiej zostały utworzone. Czy to działa? –

+1

Generalnie powinno działać. Ale wdrożenie będzie dość złożone. Na przykład muszę użyć 'WeakReference' w takim przypadku, aby nie zależało od samego obiektu. Jako techniczne rozwiązanie tego problemu działa, ale z mojego punktu widzenia wygląda dość brzydko. W każdym razie dziękuję za pomysł! – artspb

1

ConcurrentHashMap w ogólnych apartamentów dla moich potrzeb, ale nie mogę znaleźć sposób, aby podjąć działanie atomowy

Dlaczego nie skorzystać remove w ConcurrentHashMap? Wydaje się, że to jest to, czego potrzebujesz.

+0

Ale użycie polecenia "usuń" metoda Najpierw muszę jakoś uzyskać obiekt. Mogę to zrobić za pomocą 'iteratora' próbującego usunąć każdy obiekt, dopóki mi się to nie uda. Jeśli jest dużo wątków, będzie to wymagało wiele czasu, aby usunąć już usunięte wpisy. To dlatego, że poprzez 'iterator'' ConcurrentHashMap' pracujesz z pewnym stanem mapy, ale nie z prawdziwymi danymi. Z przeciwnej strony 'pollFirst()' metoda 'ConcurrentSkipListSet' działająca z rzeczywistymi danymi. W takim przypadku powinno być znacznie szybciej. – artspb