sobota, 21 czerwca 2014

Wielowątkowość - kolekcje synchronizowane i wielowątkowe, synchronizatory

Kolekcje synchronizowane


Java zawiera kolekcje synchronizowane - stare kolekcje Vector i Hashtable. Można także z każdej niesynchronizowanej kolekcji zrobić taką poprzez metodę fabrykującą Collections.synchronizedXXX np synchronizedMap. Fabryka taka tworzy obiekt który dekoruje każdą publiczną metodę opakowując ją blokiem synchronized używając instancji obiektu do blokowania.

Kolekcje synchronizowane nie mają takich metod jak putIfAbsent, ich iteratory są iteratorami fail-fast - czyli jeśli wykryją modyfikacje w trakcie iterowania wyrzucają wykątek ConcurrentModificationException. Blokowanie iteratora na czas iterowania może być bardzo kosztowne i sprawiać że program nie będzie skalowalny.


Kolekcje wielowątkowe (concurrent collections)

 

W javie 5 wprowadzono kolekcje wielowątkowe takie jak ConcurrentHashMap, CopyOnWriteArrayList, CopyOnWriteArraySet, ArrayBlockingQueue, LinkedBlockingQueue, LinkedBlockingDequeue

ConcurrentHashMap nie synchronizuje wszystkich metod zamiast tego wykorzystywany jest tu mechanizm podziału na wiele map każda ze swoją blokadą - lock striping dzięki czemu więcej wątków może symultanicznie wykonywać operacje na obiekcie mapy. Dodatkowo mapa implementuje interfejs ConcurentMap w którym są dodatkowe atomowe metody: putIfAbsent, remove, replace. Iterator takiej mapy nie wyrzuca wyjątku jeśli mapa jest modyfikowana jednak jest iteratorem weakly consistent - czyli nie musi pokazywać zmian po utworzeniu iteratora.

CopyOnWriteArrayList jest klasą thread-safe i zastępuje ArrayList - tworzy ona kopie podległej wewnętrznej tablicy za każdym razem kiedy wykonywana jest operacja dodawania, lub usuwania obiektu - dzięki temu iterator po stworzeniu może iterować na tablicy na której został zainicjowany więc nie wyrzuci wyjątku ConcurrentModificationException. Klasa taka ma zastosowanie tam gdzie dominującą operacją jest iterowanie a nie dodawanie np. listenery.

Kolejki blokujące mogą być użyte do rozwiązania problemu producent-konsumer. Zawierają metody blokujące które czekają jeśli kolejka jest pusta lub pełna.

Kolejki dequeue umożliwają pobieranie elementów także z początku kolejki dzięki czemu mogą być używane w alborytmach work-stealing w których każdy konsument ma jedną kolejkę i jeśli nie ma więcej pracy może wziąć pracę z początku innego konsumenta - dzięki temu wątki mniej będą ze sobą walczyły (less contention) i dzięki temu rozwiązanie jest bardziej skalowalne.


Metody blokujące które rzucają wyjątek IterruptedException


Każdy wątek może zostać zablokowany lub zapauzowany z różnych powodów - oczekiwaniu na blokadzie, czekanie na skończenie operacji I/O, czekanie na wybudzenie z operacji sleep. W takim wypadku proces przechodzi w stan BLOCKED, WAITING, TIMED_WAITING. Wątek który jest zablokowany musi być czekać na operacje na którą nie ma wpływu a która go wybudzi.

Nie da się zatrzymać wątku z innego wątku - można mu tylko ustawić flagę interrupt poprzez metodę interrupt. Mechanizm ten jest w większości wykorzystywane to anulowania długo trwających operacji.

Jak obsłużyć InterruptedException:
  • poprzez propagowanie go wyżej do metody wywołującej
  • poprzez obsługę - jeśli nie można go wyżej propagować - poprzez restorowanie flagi interrupted: Thread.currentThread().interrupt()
Można też pominąć obsługę jeśli pracujemy bezpośrednio na klasie Thread.

Synchronizatory

 

Semaphore - klasa przydatna np przy pulach obiektów. 

CountDownLatch - jednorazowy zatrzask który odlicza się on n do zera, wątki czekają na to aż wartość będzie równa 0. Może być użyty tylko raz.

CyclicBarrier - tak jak zatrzask blokują grupę wątków aż pewna aktywność się skończy - znana - stała liczba wątków dojdzie do bariery, następnie bariera jest resetowana a wątki mogą kontynuwać działanie. Jeśli wątek na barierze zostanie przerwany lub wystąpi timeout to reszta wątków zostanie wybudzona przez BrokenBarrierException a bariera zostanie w stanie broken. 

Phaser - jest bardziej wyrafinowaną barierą, umożliwia rejestracje i wyrejestrowywanie wątków oczekujących.

Exchanger pozwala na wymianę obiektu między wątkami w miejscu "spotkania".

 

 

Brak komentarzy:

Prześlij komentarz